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

Emm*_*uel 29 shell bash pipe read

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

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
2 1
$
Run Code Online (Sandbox Code Playgroud)

但它在 Bash 中失败了:

$ echo 1 2 3 4 5 | read a b dump
$ echo $b $a 
  
$
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*mer 39

bash 子shell上下文中运行管道的右侧,因此read不会保留对变量的更改(这是什么) - 当子shell执行时,它们会在命令结束时消失。

相反,您可以使用进程替换

$ read a b dump < <(echo 1 2 3 4 5)
$ echo $b $a
2 1
Run Code Online (Sandbox Code Playgroud)

在这种情况下,read在我们的主 shell 中运行,我们的输出生成命令在子 shell 中运行。该<(...)语法创建了一个子外壳并将其输出连接到管道,我们read使用普通<操作将其重定向到输入。因为read在我们的主 shell 中运行,变量设置正确。

正如评论中指出的那样,如果您的目标是以某种方式将字符串拆分为变量,则可以使用此处的字符串

read a b dump <<<"1 2 3 4 5"
Run Code Online (Sandbox Code Playgroud)

我认为还有更多的东西,但如果没有,这是一个更好的选择。

  • 或者甚至是`read ab dump &lt;&lt;&lt; '1 2 3 4 5'`。 (3认同)

jll*_*gre 22

这不是一个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 
Run Code Online (Sandbox Code Playgroud)

输出:

before:
after: 2 1
Run Code Online (Sandbox Code Playgroud)

  • @anarcat 这是正确的,但这里提出的问题是关于 bash 的。 (2认同)