Ban*_*uin 10 bash pipe shell-script subshell read
我已经习惯了 while 循环中bash的内置read函数,例如:
echo "0 1
      1 1
      1 2
      2 3" |\
while read A B; do
    echo $A + $B | bc;
done
Run Code Online (Sandbox Code Playgroud)
我一直在做一些make项目,拆分文件和存储中间结果变得谨慎。因此,我经常最终将单行分解为变量。虽然下面的例子效果很好,
head -n1 somefile | while read A B C D E FOO; do [... use vars here ...]; done
Run Code Online (Sandbox Code Playgroud)
这有点愚蠢,因为 while 循环永远不会运行超过一次。但没有while,
head -n1 somefile | read A B C D E FOO; [... use vars here ...]
Run Code Online (Sandbox Code Playgroud)
当我使用它们时,读取变量总是空的。我从未注意到 的这种行为read,因为通常我会使用 while 循环来处理许多类似的行。如何在没有 while 循环的情况下使用bash's readbuiltin?或者是否有另一种(甚至更好)的方法将一行读入多个(!)变量?
结论
答案告诉我们,这是一个范围界定的问题。该声明
 cmd0; cmd1; cmd2 | cmd3; cmd4
Run Code Online (Sandbox Code Playgroud)
被解释为使得命令cmd0、cmd1和cmd4在同一范围内执行,而命令cmd2和cmd3每个都被赋予自己的子shell,因此具有不同的范围。原始外壳是两个子外壳的父级。
cha*_*aos 10
这是因为您使用 vars 的部分是一组新命令。改用这个:
head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }
Run Code Online (Sandbox Code Playgroud)
请注意,在此语法中,在 之后{
和;之前必须有一个空格(分号)}。也-n1没有必要; read只读取第一行。
为了更好地理解,这可能对您有所帮助;它的作用与上面相同:
read A B C D E FOO < <(head somefile); echo $A $B $C $D $E $FOO
Run Code Online (Sandbox Code Playgroud)
编辑:
人们常说接下来的两个语句做同样的事情:
head somefile | read A B C D E FOO
read A B C D E FOO < <(head somefile)
Run Code Online (Sandbox Code Playgroud)
嗯,不完全是。第一个是来自headtobash的read内置管道。一个进程的标准输出到另一个进程的标准输入。
第二个语句是重定向和进程替换。它bash自己处理。它创建一个 FIFO(命名管道<(...)),该 FIFOhead的输出连接到该 FIFO ,并将其重定向 ( <) 到read进程。
到目前为止,这些看起来是等价的。但是当使用变量时,它可能很重要。在第一个中,变量在执行后没有设置。在第二个中,它们在当前环境中可用。
在这种情况下,每个 shell 都有另一种行为。请参阅它们所在的链接。在bash你可以解决该行为与指挥编组{},进程替换(< <())或以下字符串(<<<)。