问题描述
我有一个仅包含一行的输入文件:
I have an input file that contains only one line:
$ cat input
foo bar
我想在我的脚本中使用这一行,我知道有3种方法来获取它:
I want to use this line in my script and there are 3 ways to get it that I know of:
line=$(cat input)
line=$(<input)
IFS= read -r line < input
例如,使用命令替换意味着我产生了一个子shell,而对于read
我却没有,对吗?还有什么其他区别,有没有一种方法比其他方法更可取?我还注意到(使用strace
)由于某些原因,只有read
会触发系统调用openat
.其他人怎么可能不这样做?
For example, using command substitution means I spawn a subshell, whereas with read
I do not, correct? What other differences are there and is one way preferred over the others? I also noticed (with strace
) that only read
triggers the syscall openat
for some reason. How is it possible that the others don't?
$ strace ./script |& grep input
read(3, "#!/usr/bin/env bash\n\ncat > input"..., 80) = 80
read(255, "#!/usr/bin/env bash\n\ncat > input"..., 167) = 167
read(255, "\nline=$(cat input)\nline=$(<input"..., 167) = 60
read(255, "line=$(<input)\nIFS= read -r line"..., 167) = 41
read(255, "IFS= read -r line < input\n", 167) = 26
openat(AT_FDCWD, "input", O_RDONLY) = 3
推荐答案
-
line=$(cat input)
是读取整个文件的POSIX方法.它需要一个叉子.line=$(cat input)
is the POSIX way of reading the entire file. It requires a fork.line=$(< input)
是读取整个文件的效率稍高的Bashism.它也可以分叉,但不必执行.line=$(< input)
is a marginally more efficient Bashism for reading the entire file. It also forks, but doesn't have to execve.未提及,但
mapfile
/readarray
是将行中的整个文件逐行读取到数组中的高效Bashisms.没有叉子.Not mentioned but
mapfile
/readarray
are significantly more efficient Bashisms for reading the entire file line-by-line into arrays. No forks.IFS= read -r line < input
是POSIX方式,无需子shell即可读取单行.没有叉子.IFS= read -r line < input
is the POSIX way of reading a single line without a subshell. No forks.之所以只看到后者打开文件,是因为其他人在子shell中进行了操作,而您未指定
-f
来跟踪子进程.The reason why you only see the latter opening the file is simply that the others do it in a subshell, and you haven't specified
-f
to trace child processes.这篇关于"$(cat file)","$(< file)"和"$(cat file)"之间的区别是什么?和“阅读...<文件"对于只有一行的文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!