For the unquoted example, each \\
pair passes one backslash to grep, so 4 backslashes pass two to grep, which translates to a single backslash. 6 backslashes pass three to grep, translating to one backslash and one \c
, which is equal to c
. One additional backslash does not change anything, because it is translated \c
-> c
by the shell. Eight backslashes in the shell are four in grep, translated to two, so this does not match anymore.
For the example in double quotes, note what follows your second quote from the bash manpage:
The backslash retains its
special meaning only when followed by one of the following characters:
$, `, ", \, or newline.
I.e. when you give an odd number of backslashes, the sequence ends in \c
, which would be equal to c
in the unquoted case, but when quoted, the backslash looses its special meaning, so \c
is passed to grep. That is why the range of "possible" backslashes (i.e. those that make up a pattern matching your example file) slides down by one.
Here (linebreaks added),
$ task add "first line doesn\'t say much
Second line says a lot but part of this line does not appear in the
resulting description 'truncate -s0 !(temp_file | temp_dir)' truncates
all files to 0 bytes as shown by: '`wc -l *`'"
the whole string is double-quoted, so command substitutions and other expansions will run there. That happens in the shell, before task
sees that string, and you'll need to prevent it with backslashes or putting that part in single quotes.
E.g.
$ printf "%s\n" "...shown by: '\`wc -l *\`'"
...shown by: '`wc -l *`'
So,
task add "...shown by: '\`wc -l *\`'"
would pass the string ...shown by: '`wc -l *`'
to task
. It's up to it what does with that.
If you don't want to use backslashes, here's the way to put it in single quotes:
# aaaaaaaaaaaaaaaaBBBBBBBBBBBaaa
$ printf "%s\n" "...shown by: '"'`wc -l *`'"'"
...shown by: '`wc -l *`'
(The a
's mark the double-quoted parts, the B
's the single-quoted parts. They are just concatenated on the shell command line. The literal single quotes are within the double-quoted strings.)
As for the single quote and the backslash, you don't need to escape a single quote within double quotes, and in fact the backslash will remain there:
$ printf "%s\n" "foo'bar"
foo'bar
$ printf "%s\n" "foo\'bar"
foo\'bar
From what you show, it seems like task
removes at least the first single-quoted string from the argument (plus a word after that, since the removed part was 't say much ... 'truncate
)
The shell will not do that, this works fine:
$ printf "%s\n" "a 'quoted string' to test"
a 'quoted string' to test
What's causing the shell to remove the part of the argument to task
between \
(backslash) and -s
,
It's highly likely it's not the shell doing that.
and how do you prevent the shell from interpreting the above single-quoted command substitution (i.e. '`wc -l *`'
)?
It's not single-quoted, it's double-quoted with quoted single quotes next to it.
Best Answer
The
'
single quote character in yourecho
example gets it literal value (and loses its meaning) as it enclosed in double quotes ("
). The enclosing characters are the double quotes.What you can do is print the single quotes separately:
or escape the
$
: