What is the difference between
grep apple file and
grep "apple" file? What does putting the quotation marks do? They both appear to work and do the exact same thing (display same line).
The quotation marks have an effect on what characters your shell considers special and to have a syntactic meaning. In your example this doesn't make a difference because
apple contains no such characters.
But consider another example:
grep apple tree file will search for the word
apple in the files
grep "apple tree" file will search the word
apple tree in the file
file. The quotation marks tell bash, that the word space in
"apple tree" does not start a new parameter but shall be part of the current parameter.
grep apple\ tree file would produce the same result, because
\ tells bash to disregard the special meaning of the following character and treat it literally.
Double quotes allow evaluation, single quotes prevent evaluaton, no quotes allow wildcard expansion, when used on command line. As contrived examples:
[user@work test]$ ls . A.txt B.txt C.txt D.cpp # The following is the same as writing echo 'A.txt B.txt C.txt D.cpp' [user@work test]$ echo * A.txt B.txt C.txt D.cpp [user@work test]$ echo "*" * [user@work test]$ echo '*' * # The following is the same as writing echo 'A.txt B.txt C.txt' [user@work test]$ echo *.txt A.txt B.txt C.txt [user@work test]$ echo "*.txt" *.txt [user@work test]$ echo '*.txt' *.txt [user@work test]$ myname=is Fred; echo $myname bash: Fred: command not found [user@work test]$ myname=is\ Fred; echo $myname is Fred [user@work test]$ myname="is Fred"; echo $myname is Fred [user@work test]$ myname='is Fred'; echo $myname is Fred
Understanding the way quotes work is pivotal to understanding Bash. For example:
# for will operate on each file name separately (like an array), looping 3 times. [user@work test]$ for f in $(echo *txt); do echo "$f"; done; A.txt B.txt C.txt # for will see only the string, 'A.txt B.txt C.txt' and loop just once. [user@work test]$ for f in "$(echo *txt)"; do echo "$f"; done; A.txt B.txt C.txt # this just returns the string - it can't be evaluated in single quotes. [user@work test]$ for f in '$(echo *txt)'; do echo "$f"; done; $(echo *txt)
You can use single quotes to pass a command via a variable. Single quotes will prevent evaluation. Double quotes will evaluate.
# This returns three distinct elements, like an array. [user@work test]$ echo='echo *.txt'; echo $($echo) A.txt B.txt C.txt # This returns what looks like three elements, but it is actually a single string. [user@work test]$ echo='echo *.txt'; echo "$($echo)" A.txt B.txt C.txt # This cannot be evaluated, so it returns whatever is between quotes, literally. [user@work test]$ echo='echo *.txt'; echo '$($echo)' $($echo)
You can use single quotes inside double quotes and you can use double quotes inside double quotes, but double quotes inside single quotes
should not be done (without escaping them) will not be evaluated, they will be interpreted literally. Single quotes within single quotes should not be done (without escaping them).
You'll need to gain a thorough understanding of quotes to use Bash effectively. Very important!
As a general rule, I don't use quotes if I want Bash to expand something into elements (like an array), I use single quotes for literal strings that are not to be altered, and I make liberal use of double quotes for variables that are likely to return any type of string. This is to ensure that spaces and special characters will be preserved.