我正在尝试查看目录中的文件数量/tmp/
。为此,我认为这个命令可以工作:
watch sh -c 'ls /tmp/|wc -l'
但它的工作似乎ls
没有任何争论。也就是说,我在~
,并且我在那里得到文件数量而不是/tmp/
.我找到了一个解决方法,似乎有效:
watch sh -c 'ls\ /tmp/|wc -l'
但为什么我需要逃避ls
和之间的空格/tmp/
?命令如何转换,watch
以便ls
将输出提供给wc
,但/tmp/
不作为参数传递给ls
?
答案1
差异可以通过以下方式看出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
在反引号的情况下,ls /tmp
作为单个参数传递给-c
to sh
,它按预期运行。如果没有这个反引号,命令在watch
运行时会进行分词sh
,然后运行提供的sh
,因此 onlyls
作为参数传递给-c
,这意味着子子sh
将仅运行一个裸ls
命令,并列出当前工作的内容目录。
那么,为什么会变得复杂呢sh -c ...
?为什么不直接跑呢watch 'ls /tmp|wc -l'
?
答案2
命令主要有两类watch
(定期运行命令的命令watch
不是标准命令,甚至有些系统会watch
执行完全不同的操作,例如在 FreeBSD 上监听另一个 tty 线路)。
一种已经将其参数与空格的串联传递给 shell(它实际上确实是 call sh -c <concatenation-of-arguments>
),另一种只是运行使用指定参数指定的命令而不调用 shell。
你处于第一种情况,所以你只需要:
watch 'ls /tmp/|wc -l'
当你这样做时:
watch sh -c 'ls /tmp/|wc -l'
你watch
实际运行:
sh -c 'sh -c ls /tmp/|wc -l'
并sh -c ls /tmp/
正在运行ls
内联脚本,其中$0
是/tmp/
(因此ls
在不带参数的情况下运行并列出当前目录)。
第一类中的一些watch
实现(例如 Linux 上的 procps-ng 中的实现)接受一个-x
选项,使它们的行为类似于watch
第二类。因此,有了那里,您可以执行以下操作:
watch -x sh -c 'ls /tmp/|wc -l'