grep
sed
如果您提供文件名参数,则忽略 stdin:
$ echo foo > test.txt
$ echo foobar | grep f test.txt
foo
$ echo foobar | sed -e 's/foo/bar/' test.txt
bar
这是既定的最佳实践吗?如果是这样,为什么?
答案1
程序知道文件是否在其命令行上指定。它无法知道 stdin 上是否有可用的输入(除了尝试读取它),并且如果有输入,程序也无法知道该输入是否是供其使用的。因此,唯一明智的选择是根据程序的调用方式(命令行参数、环境变量、配置文件等)制定明确的规则,来决定是否从 stdin 读取。
例如,典型的文本实用程序 ( cat
、sort
、grep
、awk
、perl -p
、 …) 如果未提供文件,则从 stdin 读取;如果有,则从指定文件读取。解释器遵循类似的约定,例如,sh
不带参数从标准输入读取命令,同时sh script_file_name
从指定文件读取命令(如果需要,则让脚本读取 stdin)。还有一个常见的约定,如果-
出现在预期输入文件名的位置,则程序将从 stdin 读取。
考虑一个 shell 片段,例如
somecommand | while read line; do
process "$line"
done
您需要知道是否process
从标准输入读取。不存在“测试是否提供 stdin”这样的事情:它在那里,但调用程序的用户知道他是否希望读取 stdin。
答案2
我找到的答案就是它的设计方式。如果您想从标准输入和文件中读取数据,请使用echo foobar | grep f - test.txt
.从man grep
grep searches the named input FILEs (or standard input if no files are
named, or if a single hyphen-minus (-) is given as file name) for lines
containing a match to the given PATTERN. By default, grep prints the
matching lines.