How to prevent command substitution on the command line?

Use single-quote strong quoting:

printf '%s\n' '`wc -l *`'

And if you want to also include single quotes in that argument passed to printf, you'd need to use different quotes for ' itself like:

printf '%s\n' '`wc -l *` and a '"'"' character'

Or:

printf '%s\n' '`wc -l *` and a '\'' character'

Other alternatives include escaping the ` with backslash inside double quotes:

printf '%s\n' "\`wc -l *\` and a ' character"

Or have ` be the result of some expansion:

backtick='`'
printf '%s\n' "${backtick}wc -l *${backtick} and a ' character"

Also note:

cat << 'EOF'
`wc -l *` and a ' character and a " character
EOF

to output arbitrary text without having to worry about quoting (note the quotes around the first EOF).

You can also do:

var=$(cat << 'EOF'
echo '`wc -l *`'
EOF
)

Which with ksh93 or mksh you can optimise to:

var=$(<<'EOF'
echo '`wc -l *`'
EOF
)

(also works in zsh, but still runs cat in a subshell there) for $var to contain literally echo '`wc -l *`'.

In the fish shell, you can embed ' within '...' with \':

printf '%s\n' '`wc -l *` and a \' character'

but anyway ` is not special there, so:

printf '%s\n' "`wc -l *` and a ' character"

would work as well.

In rc, es or zsh -o rcquotes, you can insert a ' within '...' with '':

printf '%s\n' '`wc -l *` and a '' character'

See How to use a special character as a normal one? for more details.


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.