当我使用 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