我正在尝试将管道的输出放入变量中。我尝试了以下操作:
echo foo | myvar=$(</dev/stdin)
echo foo | myvar=$(cat)
echo foo | myvar=$(tee)
却$myvar
是空空如也。
我不想做:
myvar=$(echo foo)
因为我不想生成子外壳。
有任何想法吗?
编辑:我不想生成子 shell,因为管道之前的命令需要编辑全局变量,而在子 shell 中无法执行此操作。它可以?事情echo
只是为了简化。它更像是:
complex_function | myvar=$(</dev/stdin)
我不明白为什么这不起作用。这适用于例如:
complex_function | echo $(</dev/stdin)
答案1
正确的解决方案是使用如下命令替换:
variable=$(complex_command)
如
message=$(echo 'hello')
(或者就此而言,message=hello
在本例中)。
您的管道:
echo 'hello' | message=$(</dev/stdin)
或者
echo 'hello' | read message
实际上有效。唯一的问题是您使用的 shell 将在子 shell 中运行管道的第二部分。当管道退出时,该子 shell 会被销毁,因此 的值$message
不会保留在 shell 中。
在这里你可以看到它的工作原理:
$ echo 'hello' | { read message; echo "$message"; }
hello
...但是由于子 shell 的环境是独立的(并且消失了):
$ echo "$message"
(无输出)
对您来说,一种解决方案是切换到ksh93
更智能的解决方案:
$ echo 'hello' | read message
$ echo "$message"
hello
另一个解决方案bash
是设置lastpipe
shell 选项。这将使管道的最后一部分在当前环境中运行。然而,这在交互式 shell 中不起作用,因为lastpipe
要求作业控制未处于活动状态。
#!/bin/bash
shopt -s lastpipe
echo 'hello' | read message
echo "$message"
答案2
使用命令替换:
myvar=`echo foo`
或者
myvar=$(echo foo)
答案3
给定一个修改全局变量并在 stdout 上输出内容的函数:
global_variable=old_value
myfunction() {
global_variable=new_value
echo some output
}
在ksh93
mksh R45 或更新版本中,您可以使用:
var=${
myfunction
}
然后:
$ print -r -- "$global_variable, $var"
new_value, some output
${ ...; }
是一种不会生成子 shell 的命令替换形式。对于内置命令的命令,不要让它们将输出写入管道(为此,您需要不同的进程在管道上读取和写入以避免死锁),ksh93
而是让它们不输出任何内容,而是收集它们的内容本来会输出来弥补扩张。mksh
使用临时文件代替。
$ ksh -c 'a=${ b=123; echo foo;}; print -r -- "$a $b"'
foo 123
fish
的命令替换的行为也类似于 ksh93 的${ ...; }
:
$ fish -c 'set a (set b 123; echo foo); echo $a $b'
foo 123
在大多数其他 shell 中,您将使用临时文件:
myfunction > file
var=$(cat file) # can be optimised to $(<file) with some shells
在 Linux 上,使用bash
4.4 或更早版本或zsh
(使用临时文件<<<
),您可以执行以下操作:
{
myfunction > /dev/fd/3 &&
var=$(cat<&3)
} 3<<< ''
在 中zsh
,您还可以执行以下操作:
() {
myfunction > $1
var=$(<$1)
} =(:)
在类似 Korn 的 shell 中,例如 ksh、zsh 或 bash,命令替换,无论是$(cmd...)
标准形式还是$(<file)
或 ${ cmd...; }
变体,都会去除所有尾随换行符(来自file
或 的输出cmd
)。看shell:在命令替换中保留尾随换行符('\n')了解如何解决这个问题。
在 中fish
,set var (cmd)
将 的输出的每一行分配cmd
给数组的单独元素$var
。无论是输出还是.$var
将包含相同的内容。从版本 3.4.0 开始,还支持类似 Korn 的 shell 中的行为(删除所有尾随换行符)。cmd
foo
foo<newline>
fish
set var "$(cmd)"
答案4
我会使用一个临时文件来存储复杂函数的结果,然后从临时文件中读取值进行处理。
# Create a temp file for storage
tmppath=$(mktemp)
# run the command and get the output to the temp file
complex_command > "${tmppath}"
# read the file into variable
message=$(cat "${tmppath}")
# use the variable
echo "$message"
rm -f "${tmppath}"
使用方法mktemp
可以参考如何在shell脚本中创建临时文件?