通过命令的参数向命令提供输入与通过 shell 重定向运算符提供输入有什么区别?

通过命令的参数向命令提供输入与通过 shell 重定向运算符提供输入有什么区别?

当我使用 shell 的重定向运算符向命令提供(不存在的)文件名时grep,shell 会显示有关该文件不存在的错误消息。但是,当我提供相同的文件名作为命令的参数时grep,命令本身会显示相应的错误消息grep。这是为什么?

这是我正在谈论的内容的演示。当我运行命令时:

$ grep 'root' /etc/passw

我收到以下错误消息:

grep: /etc/passw: No such file or directory

但是当我通过 shell 重定向以这种方式运行命令时:

$ grep 'root' < /etc/passw

相反,我收到以下错误消息:

bash: /etc/passw: No such file or directory

这两种指定输入文件名的方法有什么区别,让它们这样做有什么意义吗?

答案1

在您的第一个命令 ( $ grep 'root' /etc/passw) 中,您给出参数,grep它将其解释为文件名并搜索它。它 ( grep) 失败,因此会向您传达发生的情况。 grep 会解释您的输入并对其进行操作。

在第二个命令 ( grep 'root' < /etc/passw) 中,您使 shell(此处:bash)通过管道传输/etc/passw到 的标准输入grep。它 ( bash) 无法找到它,因此它会向您传达这一信息。在这里,bash 解释您的输入并对其进行操作。

第二个命令在概念上相当于在标准输出上打印给定文件的$ bash-cat /etc/passw | grep 'root'wherebash-cat操作。cat然后它会被重定向到grep.

$ bash-cat /etc/passw | grep 'root'

bash-cat: /etc/passw: 没有这样的文件或目录

--

如果您阅读有关管道的内容,您就会明白。 (管道:简介

答案2

当使用像这样的 I/O 重定向操作符时,shell 本身会打开文件作为命令输入作为 fd0 上的 O_RDONLY 的标准输入,该命令只能从中读取,但是当作为参数传递时,由命令本身来处理打开文件。

因此,如果您有一个程序(比方说awk)并使用<重定向来传递文件名,并且您尝试打印FILENAME它打开的文件,它将被报告-(意味着输入是标准输入);请参阅以下输出:

awk '{ print FILENAME }' --infile
--infile

awk '{ print FILENAME }' <--infile
-

另一个优点是,如果文件名以连字符开头,shell 将自行处理它,但如果您将其作为参数传递给命令(比如说grep),它会抱怨,因为它认为提供的选项无效。

grep root --infile
grep: unrecognized option '--infile'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

标准的、符合标准的命令--通过告诉命令它的选项参数结束来避免此错误。您还可以使用 提供文件的绝对路径或相对路径./--infle,或者让 shell 通过使用命令打开它command <--infile

注意:使用 与<inputfile command是相同的变体command <inputfile

另一个优点是如果该文件不存在或 shell 无法打开它,那么您的命令将不会执行。

awk 'BEGIN{ print "ifrun" }' < non-existing_file
-bash: non-existing_file: No such file or directory

awk 'BEGIN{ print "ifrun" }' non-existing_file
ifrun

相关内容