bash:从管道分配变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42963395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash: Assign variable from pipe?
提问by agc
In bash
, what's the most efficient way to assign a variable using piped input -- using only left to right syntax? Suppose the left side of the pipe is seq 3
, so we'd want:
在 中bash
,使用管道输入分配变量的最有效方法是什么——仅使用从左到右的语法?假设管道的左侧是seq 3
,所以我们想要:
seq 3 | x=<put some code here>
NB: Not an answer, although probably functionally equivalent:
注意:不是答案,虽然可能在功能上是等效的:
x=`seq 3`
...because seq 3
is not on the leftside of a pipe.
...因为seq 3
不在管道的左侧。
For this Q, please ignore the possibility of exceeding the variable's memory, which pipes could certainly do.
对于这个问题,请忽略超出变量内存的可能性,管道肯定可以做到。
回答by Charles Duffy
This is covered in detail in BashFAQ #24.
这在BashFAQ #24中有详细介绍。
You can reliablyuse a variable collected on the right-hand side of a pipeline only if the code referencing it is alsoon the right-hand side of that pipeline.
只有当引用它的代码也在该管道的右侧时,您才能可靠地使用在管道右侧收集的变量。
#!/bin/bash
echo "hello" | { read -r var; echo "Read value: $var"; }
echo "After the pipeline exited, var contains: $var"
Typical output is:
典型的输出是:
Read value: hello
After the pipeline exited, var contains:
The POSIX sh specification neither requires nor precludes the right-hand side of a pipeline being executed in the same shell which later executes subsequent commands. Thus, a shell mayexecute the read
on the second line in the same shell where it executes the echo
on the third -- but bash, specifically, will notdo so unless the lastpipe
shell option is enabled.
POSIX sh 规范既不要求也不排除在同一 shell 中执行的管道的右侧,该 shell 稍后执行后续命令。因此,外壳可以执行read
在它执行相同的外壳在第二行echo
第三-但bash中,具体地讲,不会,除非这样做lastpipe
外壳选项启用。
回答by mklement0
To complement Charles Duffy's helpful answerwith a focus on making it workin bash
:
为了补充Charles Duffy 的有用答案,重点是使其在bash
以下方面发挥作用:
By default, and on Bash v4.1- invariably, any variable creations / modifications in a (multi-segment) pipeline happen in a subshell, so that the result will not be visible to the calling shell.
默认情况下,并猛砸v4.1-无一例外,任何变量创作/在(多段)管道修改发生在一个子shell,这样的结果将是不可见的调用shell。
In Bash v4.2+, you can set option lastpipe
to make the lastpipeline segment run in the currentshell, so that variable creations/modifications made there arevisible to it.
在Bash v4.2+ 中,您可以设置选项lastpipe
使最后一个管道段在当前shell 中运行,以便在那里进行的变量创建/修改对其可见。
For that to work in an interactiveshell, you must additionally turn off job control with set +m
.
为了在交互式shell 中工作,您必须另外关闭作业控制set +m
。
Here's a complete example (Bash v4.2+):
这是一个完整的示例(Bash v4.2+):
$ unset x; shopt -s lastpipe; set +m; seq 3 | x=$(cat); echo "$x"
1
2
3
That said,
那说,
x=$(seq 3)
(the modern equivalent of your x=`seq 3`
) is much simpler - it is POSIX-compliant and therefore works on older Bash versions too, and it requires no fiddling with global options.
(你的现代等价物x=`seq 3`
)要简单得多 - 它符合 POSIX,因此也适用于较旧的 Bash 版本,并且不需要摆弄全局选项。
回答by Isaac
piped input
管道输入
The simplest method to set a variable is to read
it:
设置变量的最简单方法是read
:
seq 3 | read -d '' x
Will also work in zsh
but not in ksh
(no NUL
allowed for the -d
option in ksh).
也可以在zsh
但不能在ksh
(ksh 中NUL
的-d
选项不允许)。
One way to use the value of x
is to do so in the subshell created by the pipe:
使用值的一种方法x
是在管道创建的子外壳中这样做:
$ seq 3 | { read -d '' x; echo "$x"; }
1
2
3
Note that the exit condition of read is of failure (because no '' character was found). More details could be found in Bash FAQ 24
注意read的退出条件是failure(因为没有找到''字符)。更多细节可以在Bash FAQ 24 中找到
In ksh and zsh the value could be used after the pipe has ended (using a char that is not in the input (but not NUL) to make ksh also work):
在 ksh 和 zsh 中,可以在管道结束后使用该值(使用不在输入中的字符(但不是 NUL)使 ksh 也可以工作):
$ seq 3 | read -d ':' x
$ echo "$x"
1
2
3
That's because, originally in ksh (later in zsh) the last command on a pipe would run in the same process as the parent shell, keeping the value of the variable changed after the pipe has ended.
这是因为,最初在 ksh(后来在 zsh)中,管道上的最后一个命令将在与父 shell 相同的进程中运行,在管道结束后保持变量的值发生变化。
One way to emulate this capacity in bash is to use lastpipe
(which will only work if JOB CONTROLis disabled (inside a non-interactive script or with set +m
)):
在 bash 中模拟这种能力的一种方法是使用lastpipe
(只有在禁用JOB CONTROL时才有效(在非交互式脚本中或使用set +m
)):
$ set +m; shopt -s lastpipe
$ seq 3 | read -d '' x
$ echo "$x"
1
2
3
Capture command output
捕获命令输出
Using Process Substitution:
使用进程替换:
$ read -d '' x < <(seq 3)
$ echo "$x"
1
2
3
Or, using the old here-doc:
或者,使用旧的 here-doc:
$ read -d '' x <<-Hello
> $(seq 3)
> Hello
$ echo "$x"
1
2
3
Or, using printf:
或者,使用 printf:
$ printf -v x "$(seq 3)"
$ echo "$x"
1
2
3
回答by Gordon Davisson
You can sort-of do this, if you're willing to be flexible about what you mean by "piped input" and "left to right syntax". Try this:
如果您愿意灵活地理解“管道输入”和“从左到右语法”的含义,您可以这样做。尝试这个:
< <(seq 3) read -r -d '' var
I do not recommend this. At all. Just use var=$(seq 3)
.
我不推荐这个。在所有。只需使用var=$(seq 3)
.
回答by agc
One (revised) method, maybe not the best though, and may fail the OP criteria depending how we look at it:
一种(修订后的)方法,虽然可能不是最好的,并且可能无法满足 OP 标准,具体取决于我们如何看待它:
# load $x, echo it quoted, then unquoted.
seq 3 | { x=$(</dev/stdin) ; echo "$x" ; echo $x ; }
Output:
输出:
1
2
3
1 2 3
This cat
variant works in POSIX shells (yash
, dash
):
此cat
变体适用于 POSIX shell ( yash
, dash
):
seq 3 | { n=$(cat /dev/stdin) ; echo "$n" ; echo $n ; }
回答by Sohail Si
You can use a temporary file:
您可以使用临时文件:
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 ); echo x is $x
The following cleans up after use:
使用后清理如下:
seq 3 >/var/tmp/agc-bashvar1; x=$(cat /var/tmp/agc-bashvar1 ); rm /var/tmp/agc-bashvar1
seq 3 >/var/tmp/agc-bashvar1; x=$(cat /var/tmp/agc-bashvar1 ); rm /var/tmp/agc-bashvar1
Then
echo x is $x
然后
echo x is $x
Rationale: Based on @charles-duffy 's answer, you cannot survive a variable based on content received directly at the right hand side of a pipe. So why not use an external place to store the content it as a side effect (as opposed to a no-side-effect pipeline).
基本原理:根据@charles-duffy 的回答,您无法根据直接在管道右侧接收到的内容来保留变量。那么为什么不使用外部位置将内容存储为副作用(而不是无副作用管道)。
Make sure the temporary filename is not used by other programs.
确保其他程序未使用临时文件名。