Check if first character is the same as the last character?

You need

grep -E '^([a-zA-Z]).*\1$'

capture first character within (...) and use its back-reference as last character and skip everything else between .*. the -E switch enables the Extended Regular Expression match so we no need to escape capture group within our grep command but; you can also do as following and to portability:

grep '^\([a-zA-Z]\).*\1$'

if you want to output line with a single character only (however this also known as first and last character is the same), you can define its existence optionally, try:

grep -- '^\([a-zA-Z]\)\(.*\1\)\{0,1\}$'

\{0,1\} matches none-or-one occurrence of pattern .*\1 above.

or to match this on every single byte character like above are:

grep -- '^\(.\)\(.*\1\)\{0,1\}$'

By default grep is using --basic-regexp (Basic-Regular-Expression, BRE) pattern matching, which the meta-characters like ?, +, {, |, (, and ) lose their special meaning and match literally and to use them as regex, we need to use escaped types \?, \+, \{, \|, \(, and \) or just switch PATTERN Matching to ERE with -E (But note that POSIX EREs don't have back-references).


To check if a string were the same characters of length N:

grep -- '^\([a-zA-Z]\{N-HERE\}\)\(.*\1\)\{0,1\}$'

Like for 3 length of characters:

grep -- '^\([a-zA-Z]\{3\}\)\(.*\1\)\{0,1\}$'

again, as said above, this will return line(s) like only 3 (N in general) character length xxx, if you don't want these, change to:

grep -- '^\([a-zA-Z]\{3\}\).*\1$'

If processing lines of text, awk is the most obvious:

awk 'length>1 && substr($0,1,1)==substr($0,length,1)' file

If this is for a shell variable:

case $var in ''|?) echo no;; "${var#"${var%?}"}"*) echo yes;; *) echo no;; esac
[ "${#var}" -gt 1 ] && [ "${var%"${var#?}"}" = "${var#"${var%?}"}" ]