9

I don't remember the exact commands and tricks that I use sometimes which solves much of the work, so I try to log them into a file for future reference. What I typically do is just put whole command in echo and append it to the file quickly.

This has always worked, but the following situation arrived for first time, where I was not able to do as stated above.

Successfull logging

$ echo "cat file1.txt | paste -d, - - ## Step 3 " >> ~/globalLog.txt

Got stuck here

$ echo "cat file2.txt  | sed 's/"//g' > file3.txt ## Step 2 " >> ~/globalLog.txt

The above is giving a obvious error, as the quotes are not being properly closed (dropping to the second command propmt (PS2 I guess?) for completing the command i.e. >_ in my case), the single(') quotes are being used by the sed command and the double(") quotes are being used in one the sed expression for replacement.

How would I enclose the complete command in such situation ?

1
  • It looks like you're trying to log a command before executing it. Are you aware of set -v and set -x?
    – derobert
    Commented Oct 24, 2012 at 20:16

5 Answers 5

13

You can entirely avoid the need to quote using here documents. Note that setting the label in single/double quotes(as in "EOF" in the example below) disables variable and command evaluation within the text.

cat <<"EOF" >>~/globalLog.txt
cat file2.txt  | sed 's/"//g' > file3.txt ## Step 2
EOF
3
  • This should work in any POSIX shell.
    – jordanm
    Commented Oct 24, 2012 at 15:33
  • @jordanm, thank you. Deleted the reference to bash.
    – iruvar
    Commented Oct 24, 2012 at 15:39
  • 3
    You might want to note the importance of the double-quotes around EOF. Without them, the here text is subject to variable expansion, which is sometimes useful. Commented Oct 24, 2012 at 15:43
7

You have many choices, and each of them can be convenient in different situations.

  1. Double quote the whole string as one, and escape the literal double quotes inside (easy to read if you have only one such occurrence, but you could end up with a picket fence):

    echo "cat file2.txt  | sed 's/\"//g' > file3.txt ## Step 2 " >> ~/globalLog.txt
    
  2. Use different quotes for the different parts of the string:

    echo "cat file2.txt  | sed 's/"'"'"//g' > file3.txt ## Step 2 " >> ~/globalLog.txt
    
  3. Use echo's ability to process multiple arguments. This is applicable if only a single word contains the offending character, since the result will typically have a space between each argument, so it won't work for your string. Alternative example:

    echo 'foo"' "'bar"
    

    prints

    foo" 'bar
    
  4. Use multiple echo -n statements (or printf %s) followed by an echo without -n:

    echo -n "cat file2.txt  | sed '" >> ~/globalLog.txt
    echo -n 's/"' >> ~/globalLog.txt
    echo "//g' > file3.txt ## Step 2 " >> ~/globalLog.txt
    
  5. Don't use quotes at all, but escape all special characters:

    echo cat\ file2.txt\ \ \|\ sed\ \'s/\"//g\'\ \>\ file3.txt\ \#\#\ Step\ 2\  >> ~/globalLog.txt
    

Note that it's not possible to escape single quotes in a single quoted string.

And if in doubt, Use More Quotes™.

In your case, however, it looks like you're logging a command before executing it. There's already a very nice solution for working with commands as text.

1
  • 1
    My usual method (which is the simplest for programmatically quoting unknown data) is to enclose the whole thing in single quotes, then break out and backslash escape any that are inside. e.g. 'don'\''t' - this is similar to your "..."'"'"..." example but slightly easier to follow.
    – Random832
    Commented Oct 24, 2012 at 17:06
6

There is a simple, systematic and POSIX-compliant way to quote any string. You only need to remember two rules:

  1. Quote apostrophes (single quotes) with a backslash like so: \'
  2. Quote everything other than apostrophes by surrounding it with apostrophes like so: 'printf "foo\n"'

To illustrate how to use these rules together, the word don't can be systematically quoted like this: 'don'\''t'

You can often find a more readable way of quoting strings, but when things get complicated, this is the reliable way to get the quoting you want.

The quoted form of the string in the question is:

$ echo 'cat file2.txt  | sed '\''s/"//g'\'' > file3.txt ## Step 2 ' >> ~/globalLog.txt
3

just escape the " like so:

echo "cat file2.txt  | sed 's/\"//g' > file3.txt ## Step 2 " >> ~/globalLog.txt
2
1

Just

$ cat >> ~/globalLog.txt
<now type your command>
echo "cat file2.txt  | sed 's/"//g' > file3.txt ## Step 2 "
<hit ctrl-d>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .