没有这样的“规则”。有些程序从STDIN接受输入,有些则没有。如果程序可以从STDIN中获取输入,则可以将其通过管道传递给它,否则不能通过管道传递给它。
您通常可以通过考虑程序的工作来判断程序是否将接受输入。如果程序的任务就是以某种方式操纵内容文件(例如grep
,sed
,awk
等),一般需要从STDIN输入。如果它的工作是操作文件本身(例如mv
,rm
,cp
)或进程(例如kill
,lsof
),或对某事返回信息(例如top
,find
,ps
),那么它没有。
另一种思考方式是参数和输入之间的区别。例如:
mv foo bar
在上面的命令中,mv
没有任何输入。给出了两个论点。它不知道或不在乎这两个文件中的内容,它只是知道这些是其参数,因此应该对其进行操作。
另一方面
sed -e 's/foo/bar/' < file
--- -- ------------ ----
| | | |-> input
| | |------------> argument
| |--------------------> option/flag/switch
|------------------------> command
在这里,sed
已经给出了输入以及一个参数。由于它接受输入,因此可以从STDIN读取它并可以通过管道传递到它。
当参数可以作为输入时,它将变得更加复杂。例如
cat file
这file
是给的参数cat
。确切地说,文件名 file
是参数。但是,由于它cat
是一个处理文件内容的程序,因此其输入是在内部的file
。
可以使用strace
跟踪程序进行的系统调用的程序来说明这一点。如果我们运行cat foo
通过strace
,我们可以看到,该文件foo
被打开:
$ strace cat foo 2| grep foo
execve("/bin/cat", ["cat", "foo"], [/* 44 vars */]) = 0
open("foo", O_RDONLY)
上面的第一行显示该程序/bin/cat
已被调用,其参数为cat
and foo
(第一个参数始终为程序本身)。稍后,该参数foo
以只读模式打开。现在,将其与
$ strace ls foo 2| grep foo
execve("/bin/ls", ["ls", "foo"], [/* 44 vars */]) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "foo\n", 4foo
在这里,也ls
以自己foo
为论据。但是,没有open
调用,该参数不会被视为输入。而是ls
调用系统的stat
库(与stat
命令不同)以获取有关file的信息foo
。
总之,如果您正在运行的命令将读取其输入,则可以通过管道将其输入,如果没有,则不能。
pgrep
,pkill
和killall
命令。