为什么有些命令不从标准输入中读取?


19

我想知道什么时候应该使用管道,什么时候不应该使用管道。

举例来说,要终止处理pdf文件的某些进程,使用管道将无法执行以下操作:

ps aux | grep pdf | awk '{print $2}'|kill

相反,我们只能通过以下方式做到这一点:

kill $(ps aux| grep pdf| awk '{print $2}')

要么

ps aux | grep pdf | awk '{print $2}'| xargs kill

根据man bash(版本4.1.2):

The standard output of command is connected via a pipe to the standard input of command2.

对于上述情况:

  • 的标准输入grep是的标准输出ps。这样可行。
  • 的标准输入awk是的标准输出grep。这样可行。
  • 的标准输入kill是的标准输出awk。那不行

以下命令的stdin总是从上一个命令的stdout获取输入。

  • 为什么不能与kill或一起使用rm
  • killrm输入与grepawk输入有什么区别?
  • 有什么规定吗?

1
这不是一个答案,但你可能想看看pgreppkillkillall命令。
terdon

2
@terdon:我只是用上述场景来说明管道问题,我知道pgrep其余的都可以完美实现这一点:)
sylye 2014年

Answers:


17

有两种向程序提供输入的常用方法:

  • 向STDIN提供过程数据
  • 指定命令行参数

kill仅使用命令行参数。它不会从STDIN中读取。像这样的程序grepawk从STDIN读取的程序(如果未提供文件名作为命令行参数),并根据其命令行参数(模式,语句,标志等)处理数据。

您只能通过管道传输到其他进程的STDIN,而不能通过命令行输入。

通用规则是程序使用STDIN处理任意数量的数据。所有额外的输入参数,或者通常只有很少的输入参数,都由命令行参数传递。如果命令行会变得很长(例如对于较长的awk程序文本),则通常有可能从额外的程序文件(的-f选项awk)中读取这些内容。

要将程序的STDOUT用作命令行参数,请使用$(...)或在有大量数据的情况下使用xargsfind也可以直接使用-exec ... {} +

为了完整起见:要将命令行参数写入STDOUT,请使用echo


1
我们怎么知道一个命令只接受参数而不接受STDIN?有没有系统的或程序化的方式,而不是猜测或从手册页中读取?仅阅读手册页,就无法确定该命令是否可以使用STDIN的任何具体线索,因为STDIN也是手册页显示方式中参数的一部分。例如,gzip在提要中,并没有说它必须以FILENAME作为输入。我正在寻找一种更系统的方法来确定这一点。
sylye 2014年

对于某些命令,还有一个“-”自变量表示“ stdin”(或“ stdout”)。
伊曼纽尔

是否会xargs精确地允许您“通过管道传递命令行参数”?
T. Verron 2014年

@ T.Verron是的,这是的任务xargs。如有必要,它将多次调用该命令(命令行大小受到限制),并具有许多其他选项。
jofel 2014年

2
说明文字将描述如何使用该程序。例如,gzip说:“ gzip程序使用Lempel-Ziv编码(LZ77)压缩和解压缩文件。如果未指定文件,则gzip将从标准输入压缩或解压缩为标准输出。” 如果手册页未提及标准输入,则不会使用它。
艾伦·舒特科

16

这是一个有趣的问题,它涉及Unix / Linux哲学的一部分。

那么,是什么样的程序之间的差异grepsedsort一方面是和killrmls,另一方面?我看到两个方面。

过滤器方面

  • 第一种程序也称为过滤器。他们从文件或STDIN中获取输入,对其进行修改,并生成一些输出,大部分输出到STDOUT。它们应与其他程序一起在管道中用作源和目标。

  • 第二种程序作用于输入,但是它们给出的输出通常与输入无关。kill正常工作时没有输出,也没有ls。刚刚有一个返回值来显示成功。它们通常不从STDIN接收输入,但大多数将输出提供给STDOUT。

对于这类程序ls,过滤器方面的效果不佳。它当然可以有一个输入(但不需要一个),并且输出与该输入密切相关,但是它不能用作过滤器。但是,对于这种程序,另一个方面仍然有效:

语义方面

  • 对于过滤器,其输入没有语义含义。他们只是读取数据,修改数据,输出数据。这是数字值列表,某些文件名还是HTML源代码都没有关系。此数据的含义仅由提供给过滤器的代码给出:的正则表达式grep,的规则awk或Perl程序。

  • 对于其他程序(例如kill或)ls,其输入具有含义表示)kill需要进程号,ls需要文件或路径名。它们无法处理任意数据,并且不是故意的。其中许多甚至不需要任何输入或参数,例如ps。它们通常不从STDIN中读取。

一个人可能会结合这两个方面:过滤器是一个程序,其输入对该程序没有语义。

我敢肯定我在某处已经读过这种哲学,但是对不起,目前我不记得任何消息来源。如果有人提供一些资料,请随时进行编辑。


5

没有这样的“规则”。有些程序从STDIN接受输入,有些则没有。如果程序可以从STDIN中获取输入,则可以将其通过管道传递给它,否则不能通过管道传递给它。

您通常可以通过考虑程序的工作来判断程序是否将接受输入。如果程序的任务就是以某种方式操纵内容文件(例如grepsedawk等),一般需要从STDIN输入。如果它的工作是操作文件本身(例如mvrmcp)或进程(例如killlsof),或对某事返回信息(例如topfindps),那么它没有。

另一种思考方式是参数和输入之间的区别。例如:

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已被调用,其参数为catand 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

总之,如果您正在运行的命令将读取其输入,则可以通过管道将其输入,如果没有,则不能。


0
  • 为什么它不能与kill或rm一起使用?

kill并且rm不需要STDIN。

  • kill,rm输入和grep,awk输入有什么区别?

对于killrm,用户提供其自定义信息作为参数,并$(cmd)帮助获取STDOUT cmd并将其转换为info参数。

对于grepawk,用户还提供参数,此外还提供STDIN将由命令处理的常规文件。 STDIN可以通过管道传递|或通过手动输入传递。

  • 有什么规定吗?

阅读手册或源代码。如果您什么都找不到,可以进行简单但可能很危险的测试:

只需使用您已经了解的参数输入您想知道的命令,然后查看命令是否暂停(什么都没有发生)。如果暂停,它实际上是在等待STDIN(你可以尝试catecho看到不同)。您手动键入Ctrl-D,命令继续(显示结果或错误)并返回。这种命令在这种情况下需要STDIN(带有您提供的参数)。

在不同情况下,同一命令可能不需要STDIN(例如,cat等待STDIN,但cat file.txt不需要)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.