我有一个仅包含一行的输入文件:
$ cat input
foo bar
我想在脚本中使用此行,并且我知道有3种方法来获取它:
line=$(cat input)
line=$(<input)
IFS= read -r line < input
例如,使用命令替换意味着我产生了一个子shell,而对于read
我却没有,对吗?还有什么其他区别,有什么方法比其他方法更可取?我还注意到(使用strace
),由于某种原因,只有read
会触发系统调用openat
。其他人怎么可能不这样做?
$ 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
答案 0 :(得分:9)
line=$(cat input)
是读取整个文件的POSIX方法。它需要一个叉子。
line=$(< input)
是用于读取整个文件的效率稍高的Bashism。它也可以分叉,但不必执行。
没有提及,但是mapfile
/ readarray
是一种高效的Bashism,可以逐行将整个文件读入数组。没有叉子。
IFS= read -r line < input
是POSIX方式,无需子shell即可读取单行。没有叉子。
之所以只看到后者打开文件,是因为其他人在子shell中进行了操作,而您没有指定-f
来跟踪子进程。