2

While trying watch bash -c 'du -h /etc/passwd && df -h' it appears that the path to file was completely ignored, and instead du -h ran through the current working directory. Same result was observed when I ran watch bash -c 'stat /etc/passwd && df -h', and stat returned with stat: missing operand error. By contrast, using watch -e "command /path/to/file" or watch "command /path/to/file" works without issues.

Why doesn't watch bash -c 'du -h /etc/passwd && df -h' work then ? Is it watch's issue or bash's issue with argument splitting ?

1 Answers1

5

watch executes commands with arguments by passing them to sh -c, so what you end up running is:

sh -c 'bash -c du -h /etc/passwd && df -h'

The shell you're running removes the first layer of quotes you applied. The -h, /etc/passwd are then passed as $0 and $1 to bash, so they're effectively ignored. Run something like:

watch 'du -h /etc/passwd && df -h'
watch "bash -c 'du -h /etc/passwd && df -h'"

To verify, using strace:

strace -fe execve -o log watch bash -c 'du -h /etc/passwd && df -h'

And log contains:

17132 execve("/usr/bin/watch", ["watch", "bash", "-c", "du -h /etc/passwd && df -h"], [/* 40 vars */]) = 0
17134 execve("/bin/sh", ["sh", "-c", "bash -c du -h /etc/passwd && df "...], [/* 42 vars */]) = 0
17135 execve("/bin/bash", ["bash", "-c", "du", "-h", "/etc/passwd"], [/* 42 vars */]) = 0
17135 execve("/usr/bin/du", ["du"], [/* 42 vars */]) = 0
17135 +++ exited with 0 +++
muru
  • 207,228