Reputation: 69
I am trying to learn shell scripting, and I am trying different things. While I was practicing I came across grep "$a$" file1
and couldn't understand the output.
I know the difference that single quotes takes the literal meaning and the double quoting tries to find the special meaning like the $a
is supposed to be variable $
.
I have file1
with content
#!/bin/sh
a=1
b=1
echo $a
echo $b
for I in 1 2 3 4 5 6 7 8
do
c=a
b=$a
b=$(($a+$c))
echo $b
done
grep "$a$" file1
gives me the whole file1
as output where
grep '$a$' file1
gives me output as it is supposed to give, like the line which ends in $a
.
Please explain why it gives the whole file content as output when grep "$a$"
is used.
Upvotes: 1
Views: 792
Reputation: 21492
"$a$"
The string "$a$"
is expanded to the value of $a
shell variable followed by literal $
(why? see below). If the $a
variable is unset, its value is interpreted as an empty string, and the result of expansion is "$"
(only the dollar sign).
The basic form of parameter expansion is "${PARAMETER}"
. The braces are not required, if PARAMETER
is not a positional parameter with more than one digit (10
, 11
, etc.), and if PARAMETER
is not followed by a character that is not to be interpreted as part of its name. Since $
begins next parameter expansion, command substitution, or arithmetic expansion, it is not interpreted as a part of the a
parameter name in our case.
Since nothing is followed by the last $
, it doesn't conform to any kind of expansion, and left intact.
Since the match-end-of-line operator ($
) matches the empty string either at the end of the string or before a newline character in the string, the pattern $
matches any line.
Therefore, grep "$a$" file
will match and print all lines in file
, if $a
is empty.
'$a$'
Single quotes protect the string from any expansion (interpretation of special characters). That is, the string is passed to the command as is.
In the case of grep '$a$' file
invocation, the pattern matches "$a"
string at the end of the line. The following describes why.
The last $
means the end of the line, as we know. The rest of dollar signs are interpreted depending on the pattern. It can be interpreted either as literal dollar sign, or the end of the line.
In the following cases, $
represents the end-of-line operator. Otherwise, $
is ordinary.
$
is last in the pattern, as in foo$
.RE_CONTEXT_INDEP_ANCHORS
is set, and is outside a bracket expression.'\(b$\)'
, or '\(b$\)\|a'
.Since
$
in our pattern is obviously not last,RE_SYNTAX_GREP
syntax, i.e. BRE,the first dollar sign is ordinary in $a$
.
$
is not ordinary?It is not ordinary, for example, in the case of extended regular expressions. That is, with the -E
or -P
options, or with egrep
or pgrep
commands, for instance (where the RE_CONTEXT_INDEP_ANCHORS
syntax bit is set).
Consider escaping the dollar sign even though it is interpreted as literal $
in the basic regular expressions. It will develop a good habit.
To escape the dollar sign within single quotes use a backslash: '\$a$'
.
Within double quotes the backslash has special meaning, so you need to escape the backslash itself: "\\\$a\$"
.
Upvotes: 0
Reputation: 6144
There is no special meaning.
I don't see any grep
in your code. I assume your are grepping from the command line and that the variable a
is undefined. Consequently, grep "$a$"
expands to grep "$"
($a
expands to nothing) and grep $
matches every line since $
matches the end of line.
[update] By 'expand', I mean shell variable expansion. Because $a
is between double quotes, the shell is replacing $a
with the value of variable a
(which is undefined). Your grep '$a$'
yields the expected result because any string between single quotes is always left untouched by the shell. Try echo "$a$"
vs echo '$a$'
.
Upvotes: 1
Reputation: 21965
To begin with ^
and $
in a grep pattern symbolizes beginning and end respectively.
In
grep "$a$" file1
$a
undergoes expansion because it is inside double quotes. In your case $a
should be undefined. So the The result of "$a$"
is $
which matches the end of every line, so you will get the entire file as output. To verify this assign some test value to a
and then run grep.
a="TestValue" # Before running grep
grep "$a$" file1
I bet you'll get nothing as output.
Now if you want to have a literal '$' inside the double quote. then you need to do
grep "\$a$" file1 # See the first $ is escaped
Above command will give you all the lines that end with $a
echo $a
b=$a
Now if you're tired of escaping you may very well use single quotes as below
grep '$a$' file1
# The first $ is literal $, and the last one symbolizes end of file.
# More over variable-expansion doesn't take place inside single quotes.
Note : The a=1
inside the file1
has no influence on the grep result as the file1
is just an input to grep
.
Upvotes: 1