bash:从管道中分配变量?

时间:2017-03-22 21:56:10

标签: bash

bash中,使用管道输入分配变量的最有效方法是什么 - 仅使用从左到右的语法?假设管道的左侧是seq 3,所以我们想要:

seq 3 | x=<put some code here>

注意:虽然功能上可能相同,但不是答案:

x=`seq 3`

...因为seq 3不在管道的左侧侧。

对于这个Q,请忽略超出变量内存的可能性,管道当然可以这样做。

6 个答案:

答案 0 :(得分:8)

BashFAQ #24中详细介绍了这一点。

只有在引用它的代码位于该管道的右侧时,您才能可靠地使用在管道右侧收集的变量

#!/bin/bash
echo "hello" | { read -r var; echo "Read value: $var"; }
echo "After the pipeline exited, var contains: $var"

典型输出是:

Read value: hello
After the pipeline exited, var contains:

POSIX sh规范既不要求也不排除在同一个shell中执行的管道的右侧,后者执行后续命令。因此,shell 可以在同一个shell中的第二行执行read,在第三行执行echo - 但是bash,具体来说,将不这样做,除非启用了lastpipe shell选项。

答案 1 :(得分:5)

bash中重点关注使其正常工作来补充Charles Duffy's helpful answer

默认情况下,在Bash v4.1- 上总是,(多段)管道中的任何变量创建/修改都发生在子shell < / strong>,以便调用shell无法看到结果。

Bash v4.2 + 中,您可以设置选项lastpipe ,使 last 管道段在< em> current shell,以便 可见的变量创建/修改。

要使用 交互式 shell ,您必须使用set +m 另外关闭作业控制。

这是一个完整的例子(Bash v4.2 +):

$ unset x; shopt -s lastpipe; set +m; seq 3 | x=$(cat); echo "$x"
1
2
3

那就是说,

x=$(seq 3)

(现代的x=`seq 3`)相当简单 - 它符合POSIX标准,因此也适用于较旧的Bash版本,并且不需要摆弄全局选项。

答案 2 :(得分:2)

设置变量的最简单方法是read它:

seq 3 | read -d '' x

这是自2.04开发以来bash特有的。可以在zsh中使用,但不能在ksh中使用。

但是,使用x值的唯一方法是在管道创建的子shell中执行此操作:

$ seq 3 | { read -d '' x; echo "$x"; }
1
2
3

请注意,读取的退出条件是失败的(因为没有找到&#39;&#39;字符)。更多细节可以在Bash FAQ 24

中找到

答案 3 :(得分:1)

如果您愿意通过“管道输入”和“从左到右的语法”灵活处理您的意思,那么您可以这样做。试试这个:

< <(seq 3) read -r -d '' var

我不推荐这个。完全没有。只需使用var=$(seq 3)

答案 4 :(得分:0)

一个(修订)方法,可能不是最好的方法,可能会失败OP标准,具体取决于我们如何看待它:

# load $x, echo it quoted, then unquoted.
seq 3 | { x=$(</dev/stdin) ; echo "$x" ; echo $x ; } 

输出:

1
2
3
1 2 3

cat变体适用于POSIX shell(yashdash):

seq 3 | { n=$(cat /dev/stdin) ; echo "$n" ; echo $n ; }

答案 5 :(得分:-1)

您可以使用一个临时文件:

seq 3 >/var/tmp/agc-bashvar1; x=$(cat /var/tmp/agc-bashvar1 ); echo x is $x

使用后将清除以下内容:

seq 3 >/var/tmp/agc-bashvar1; x=$(cat /var/tmp/agc-bashvar1 ); rm /var/tmp/agc-bashvar1

然后 echo x is $x

合理性:基于@ charles-duffy的答案,基于直接在管道右侧接收到的内容,您无法生存一个变量。因此,为什么不使用外部位置将其存储为副作用(与无副作用的管道相对)。

确保临时文件名未被其他程序使用。