Does grep distinguish a variable and the $ regex?
Matthew Barrera
I want to grep for a variable that has the string test, but I also want to make sure that it will only find test if that is the only word on a line.
So, I tried this:
string=test
echo "test" | grep "$string$"I would like to know if grep knows that the first part, $string (in grep "$string$"), is asking to find for the string test, while the last part, $ (in grep "$string $" is asking to find for test, but nothing should be after test in the line. Is grep able to distinguish $string as a variable and only $ as the regex for end of the line, or do I have to use a certain way to distinguish them apart?
1 Answer
Grep knows nothing it does not see. If grep sees $string$, it will try to match $string{end-of-line}. What happens is that the shell expands the variable $string before grep kicks in, so that grep receivestest$ as the regex.
But, given the word $string$, why is the last $ is not expanded while$string is? Because $ is not a valid variable name. This is very clear
in the POSIX specification:
If the parameter is not enclosed in braces, and is a name,the expansion shall use the longest valid name (see XBD Name), whether or not the variable represented by that name exists.
And XBD name states
In the shell command language, a word consisting solely of underscores, digits, and alphabetics from the portable character set. The first character of a name is not a digit.
And there are also special parameters, such as $$, $@, $#, etc..
If you don't want to remember all this, simply follow Gordon Davisson's adviceand escape every $ that should not introduce a variable to ensure it will
be preserved.
$ echo "$string$"
test$
$ echo "$string\$"
test$
$ echo "\$string\$"
$string$Also remember variables are expanded in double-quotes but not in single quotes.
$ echo 'test' | grep '$string$' # No match, $string is not expanded
$ echo 'test' | grep "$string$" # Match, $string is expanded
testI want to grep for a variable that has the string
test, but I also want to make sure that it will only findtestif that is the only word on a line.
For that, you need either the regex ^test$ (to anchor the string both to the start and end of line) or to use the -x flag of grep. Your original attempt would match Atest because the regex test$ is not anchored to the start of line.
$ echo Atest | grep "$string$"
Atest
$ echo Atest | grep -x "$string"
$ echo Atest | grep "^$string$" 3