在 bash 中,在管道未设置值后读取

在 bash 中,在管道未设置值后读取

对于 ksh,我使用 read 作为分隔值的便捷方法:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
2 1
$

但在 Bash 中却失败了:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
  
$

我在手册页中没有找到失败的原因,知道吗?

答案1

bash 运行管道的右侧在一个子shell上下文,因此对变量的更改(这就是所做read的)不会被保留——当子shell在命令结束时保存时,它们就会消失。

相反,您可以使用流程替代:

$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1

在本例中,read它在我们的主 shell 中运行,而我们的输出生成命令在子 shell 中运行。语法<(...)创造read一个子 shell 并将其输出连接到一个管道,我们将其重定向到普通的输入<手术。因为read在我们的主 shell 中运行,所以变量设置正确。

正如评论中指出的,如果您的目标实际上是以某种方式将字符串拆分为变量,那么您可以使用这里的字符串:

read a b dump <<<"1 2 3 4 5"

我认为还有更多的事情要做,但如果没有的话,这是一个更好的选择。

答案2

这不是一个bash错误,因为POSIX允许bashksh行为,导致您所观察到的不幸的差异。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12

此外,多命令管道中的每个命令都位于子shell环境中;然而,作为扩展,管道中的任何或所有命令都可以在当前环境中执行。所有其他命令应在当前 shell 环境中执行。

但是,使用bash 4.2更新版本,您可以lastpipe在非交互式脚本中设置该选项以获得预期结果,例如:

#!/bin/bash

echo 1 2 3 4 5 | read a b dump
echo before: $b $a 
shopt -s lastpipe
echo 1 2 3 4 5 | read a b dump
echo after: $b $a 

输出:

before:
after: 2 1

相关内容