2: Basics of shell quoting (examined through the lens of printf) -------------------------------------------------------------- Quoting allows the shell programmer to control word-splitting behaviour of the shell. Because variables may contain whitespace characters or other odd characters, the cautious programmer needs to be aware of them. Quoting is one of the most ill-understood parts of shell programming. Two basic rules [A] =================== 0. Always surround shell and environment variables (e.g., $HOME, $USER, $PATH) with double quotation marks ("). Know when it makes sense to break this rule. 1. To suppress all shell word-splitting or expansion for a string, use single quotation marks ('). The shell will pass along the string exactly as you quoted it. Using printf ============ Before drowing ourselves in quoting itself, let's quickly dissect the following command. $ printf '%s\n' tofu - ------ ------ ---- 0 1 2 3 0: bash prompt sign 1: printf itself 2: format string to printf (first argument) 3: argument(s) The printf utility (1, which is a bash builtin but is also included in GNU coreutils) understands its next argument as a format string (2). All remaining arguments (3 ...) are interpolated into the output based on the format string. Below, we'll use an extremely simple format string, "%s\n", which tells printf to produce each single argument as a string and print a following newline. Thus, the word "tofu" above is the string to print. Here's the complete output: $ printf '%s\n' tofu tofu What happens if we add arguments? The printf utility should print each argument as a string, followed by a newline. $ printf '%s\n' tofu spinach bratwurst tofu spinach bratwurst Now, let's see what happens if we change the format string: $ printf 'I like %s.\n' tofu I like tofu. And, perhaps also add arguments: $ printf 'I like %s.\n' tofu spinach bratwurst I like tofu. I like spinach. I like bratwurst. For a very practical example, try printing out a list of IP addresses inside your favorite /24 network with the following command: $ printf '172.16.80.%s\n' $( seq 254 ) Example of quoting shell variable (parameter) ============================================= It is very common for shell variables to contain numbers, filenames, date and time strings or other arbitrary input. One of the most commonly embedded characters to foil the shell programmer is a whitespace character (' '). Here's an example of our problem, a variable called FILE. Let's assume you want to programmatically refer to a filename with a space in the name (e.g. "next weekend party.pdf"). $ FILE="next weekend party.pdf" $ printf "%s\n" $FILE next weekend party.pdf Whoa! This is definitely not what we desired! What happened? First, we established a shell variable, FILE, which contained the filename with the embedded spaces. Note, that we were careful to follow the rules and use double quotes to protect the embedded whitespace. Now, we happily try to use the variable FILE. Here's an abbreviated tour through the shell's process in figuring out what to do with this line: 0 split line into tokens; 1: printf, 2: "%s\n", 3: $FILE 1 check first token, is it a command? (Yup, printf is a shell builtin.) 2 check to see if any expansion inside double-quotes needs to occur (Nope, no dollar signs ($), or backticks (`) [B].) 3 check to see if there are any parameters (shell variables) to expand (Yes! $FILE needs to be expanded.) 4 replace $FILE with the contents of the shell variable 5 split line into shell words; 1: printf, 2: "%s\n", 3: next, 4: weekend, 5: party.pdf So, compare what the user wrote on the command line $ FILE="next weekend party.pdf" $ printf "%s\n" $FILE with the shell's (internal) result after all variables have been expanded and broken into words. It is as though the user had typed: $ printf "%s\n" next weekend party.pdf Now, instead of seeing only a single argument (the full filename), the printf utility sees three arguments after the format string. And, the solution, as you have already, no doubt divined...double-quote $FILE: $ printf "%s\n" "$FILE" next weekend party.pdf Perfect! Supposing you wish to show the variable name itself? Well, then you can use single quotation marks. $ printf "%s\n" '$FILE' $FILE Try a bunch of the following permutations: printf "%s\n" "$FILE" # -- double quoted (as above) printf "%s\n" '$FILE' # -- single quoted (as above) printf "%s\n" '$FILE' "$FILE" # -- two args to printf printf "%s\n" '$FILE'" has $FILE" # -- one arg to printf printf "%s\n" "\$FILE" # -- escaped $ (like '$FILE') printf "%s\n" "\"$FILE\"" # -- output quotations, too Summary ======= Always remember to quote shell variables with double quotes. Use single quotes if you want to print the variable name itself. This was an introduction to basic quoting mechanisms. There are other features of quoting (and escaping). See the bash manpage and some resources at the bottom of this page. Footnotes ========= [A] And, to return to a familiar quotation on software engineering and systems design: Be liberal in what you accept and conservative in what you produce. [B] The unabashed purist would observe that the shell must examine the backslash to see what it is escaping. In this case, the backslash is passed through to the printf command/builtin. Resources ========= [0] http://www.mpi-sb.mpg.de/~uwe/lehre/unixffb/quoting-guide.html [1] http://www.consultix-inc.com/quoting.txt [2] http://www.greenend.org.uk/rjk/2001/04/shell.html