对于 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
允许bash
和ksh
行为,导致您所观察到的不幸的差异。
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