【问题标题】:What is the difference between "$(cat file)", "$(<file)" and "read ... < file" for files with one line?对于只有一行的文件,“$(cat file)”、“$(<file)”和“read ... < file”有什么区别?
【发布时间】:2019-01-26 23:51:28
【问题描述】:

我有一个只包含一行的输入文件:

$ 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

【问题讨论】:

  • "只有read 出于某种原因触发了系统调用 openat。其他人怎么可能不这样做?" -- 如您所知,第一个两个命令在子 shell 中读取文件。确保您要求strace 也跟踪由您跟踪的初始进程产生的子进程。

标签: bash file strace


【解决方案1】:
  • line=$(cat input) 是读取整个文件的 POSIX 方式。它需要一个叉子。

  • line=$(&lt; input) 是读取整个文件的效率略高的 Bashism。它也分叉,但不必执行。

  • 未提及,但 mapfile/readarray 是更有效的 Bashism,用于将整个文件逐行读取到数组中。没有分叉。

  • IFS= read -r line &lt; input 是 POSIX 读取单行的方式,无需子 shell。没有分叉。

你只看到后者打开文件的原因只是其他人在子shell中做的,你没有指定-f来跟踪子进程。

【讨论】:

  • 嘿。我的错误印象是$(&lt;...) 都在进行中,但你说它分叉是对的。也就是说,未来的 bash 版本肯定有可能不再这样做,从而提供更有效的实现——因此,使用 POSIX 语法不仅会将一个锁定到exec,还锁定到fork,而$(&lt;...) 可以改进为以后都不做。
猜你喜欢
  • 2019-07-10
  • 2013-12-12
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多