The difference may be seen via strace
:
$ strace -ff -o bq watch sh -c 'ls\ /tmp/|wc -l'
^C
$ strace -ff -o nobq watch sh -c 'ls /tmp/|wc -l'
^C
$ grep exec bq* | grep sh
bq.29218:execve("/usr/bin/watch", ["watch", "sh", "-c", "ls\\ /tmp/|wc -l"], [/* 54 vars */]) = 0
bq.29219:execve("/bin/sh", ["sh", "-c", "sh -c ls\\ /tmp/|wc -l"], [/* 56 vars */]) = 0
bq.29220:execve("/bin/sh", ["sh", "-c", "ls /tmp/"], [/* 56 vars */]) = 0
$ grep exec nobq* | grep sh
nobq.29227:execve("/usr/bin/watch", ["watch", "sh", "-c", "ls /tmp/|wc -l"], [/* 54 vars */]) = 0
nobq.29228:execve("/bin/sh", ["sh", "-c", "sh -c ls /tmp/|wc -l"], [/* 56 vars */]) = 0
nobq.29229:execve("/bin/sh", ["sh", "-c", "ls", "/tmp/"], [/* 56 vars */]) = 0
In the backquote case, ls /tmp
is passed as a single argument to the -c
to sh
, which runs as expected. Without this backquote, the command is instead word split when watch
runs sh
which in turn runs the supplied sh
, so that only ls
is passed as the argument to -c
, meaning that the sub-subsh
will only run a bare ls
command, and lists the contents of the current working directory.
So, why the complication of sh -c ...
? Why not simply run watch 'ls /tmp|wc -l'
?
watch "sh -c 'ls /tmp | wc -l'"
doing this command should get the desired affect. This isn't watches fault, trysh -c ls /tmp
and you'll get your home directory (but I have no idea why...)watch
incorrectly .The command that you pass towatch
is in turn fed bywatch
tosh -c
, so you're in effect doingsh -c
twice./tmp
is an argument tosh
, in that case, not an argument tols
.