对于只有一行的文件,“$(cat file)”、“$(<file)”和 "read ... < file" 之间有什么区别?
What is the difference between "$(cat file)", "$(<file)" and "read ... < file" for files with one line?
我有一个只包含一行的输入文件:
$ 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
line=$(cat input)
是读取整个文件的 POSIX 方式。它需要一个叉子。
line=$(< input)
是一种稍微更有效的 Bashism,用于读取整个文件。它也分叉,但不必执行。
未提及,但 mapfile
/readarray
是显着更有效的 Bashisms,用于将整个文件逐行读入数组。没有叉子。
IFS= read -r line < input
是 POSIX 在没有子 shell 的情况下读取单行的方式。没有叉子。
你只看到后者打开文件的原因很简单,其他人在子shell中打开文件,而你没有指定-f
来跟踪子进程。
我有一个只包含一行的输入文件:
$ 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
line=$(cat input)
是读取整个文件的 POSIX 方式。它需要一个叉子。line=$(< input)
是一种稍微更有效的 Bashism,用于读取整个文件。它也分叉,但不必执行。未提及,但
mapfile
/readarray
是显着更有效的 Bashisms,用于将整个文件逐行读入数组。没有叉子。IFS= read -r line < input
是 POSIX 在没有子 shell 的情况下读取单行的方式。没有叉子。
你只看到后者打开文件的原因很简单,其他人在子shell中打开文件,而你没有指定-f
来跟踪子进程。