ksh 有一个非常有趣的构造可以做到这一点,在此答案中详细介绍:https://stackoverflow.com/a/11172617/636849
自Bash 4.0以来,有一个内置的 mapfile 内置命令,该命令应该解决此问题:http://www.gnu.org/software/bash/manual/html_node/bash-builtins.html
,但奇怪的是,它似乎与流程替换不起作用:
foo () { echo ${BASH_SUBSHELL}; }
mapfile -t foo_output <(foo) # FAIL: hang forever here
subshell_depth=${foo_output[0]} # should be 0
但是如何在bash v3.2?
这是另一种做到这一点的方法,它足够不同,可以单独答案。我认为此方法不含子壳,bash子过程免费:
ubuntu@ubuntu:~$ bar () { echo "$BASH_SUBSHELL $BASHPID"; }
ubuntu@ubuntu:~$ bar
0 8215
ubuntu@ubuntu:~$ mkfifo /tmp/myfifo
ubuntu@ubuntu:~$ exec 3<> /tmp/myfifo
ubuntu@ubuntu:~$ unlink /tmp/myfifo
ubuntu@ubuntu:~$ bar 1>&3
ubuntu@ubuntu:~$ read -u3 a
ubuntu@ubuntu:~$ echo $a
0 8215
ubuntu@ubuntu:~$ exec 3>&-
ubuntu@ubuntu:~$
这里的诀窍是使用exec
在使用FD的读写模式下打开FIFO,这似乎具有使FIFO非阻滞的副作用。然后,您可以将命令重定向到FD而不会阻止它,然后读取FD。
请注意,FIFO将是一个有限尺寸的缓冲区,可能大约是4K,因此,如果您的命令产生的输出比这更多,则最终会再次阻止。
这个问题经常出现,同时寻找如何将任何"打印"命令的输出捕获到变量中。因此,对于任何人来说,都有可能(因为bash v3.1.0)与:
printf -v VARIABLE_NAME "whatever you need here: %s" $ID
如果您以速度调整脚本,则可以使用在功能末尾设置某些全局变量的模式,而不仅仅是"回声"它 - 谨慎使用它,有时会批评它导致很难维护代码。<<<<<<<<<<<<
这是我可以提出的 - 它有点混乱,但是foo
在顶级壳上下文中运行,并且在顶级壳中的可变a
中提供了其输出上下文:
#!/bin/bash
foo () { echo ${BASH_SUBSHELL}; }
mkfifo /tmp/fifo{1,2}
{
# block, then read everything in fifo1 into the buffer array
i=0
while IFS='' read -r ln; do
buf[$((i++))]="$ln"
done < /tmp/fifo1
# then write everything in the buffer array to fifo2
for i in ${!buf[@]}; do
printf "%sn" "${buf[$i]}"
done > /tmp/fifo2
} &
foo > /tmp/fifo1
read a < /tmp/fifo2
echo $a
rm /tmp/fifo{1,2}
这当然假设有两件事:
- 允许FIFO
- 进行缓冲的命令组被允许放入背景
我对此进行了测试以在这些狂欢版本中工作:
- 3.00.15(1)-Release(x86_64-redhat-linux-gnu)
- 3.2.48(1)-Release(x86_64-apple-darwin12)
- 4.2.25(1)-Release(x86_64-pc-linux-gnu)
附录
我不确定Bash 4.x中的mapfile
方法可以执行您想要的操作,因为该过程替换<()
会创建一个全新的bash过程(尽管不是该bash过程中的bash子壳):
$ bar () { echo "$BASH_SUBSHELL $BASHPID"; }
$ bar
0 2636
$ mapfile -t bar_output < <(bar)
$ echo ${bar_output[0]}
0 60780
$
因此,当$BASH_SUBSHELL
在这里为0时,这是因为它在该过程替换中的新壳过程60780的最高级别。
最简单的方法是删除函数并直接传递变量,例如:
declare -a foo_output
mapfile -t foo_output <<<${BASH_SUBSHELL}
subshell_depth=${foo_output[0]} # Should be zero.
否则在功能中给出了两个项目:
foo () { echo "$BASH_SUBSHELL $BASHPID"; }
您可以像以下命令之一一样使用read
(根据需要修改IFS
):
cat < <(foo) | read subshell_depth pid # Two variables.
read -r subshell_depth pid < <(foo) # Two separate variables.
read -a -r foo_arr < <(foo) # One array.
或使用readarray
/mapfile
(bash> 4):
mapfile -t foo_output < <(foo)
readarray -t foo_output < <(foo)
然后将输出转换回数组:
foo_arr=($foo_output)
subshell_depth=${foo_arr[0]} # should be 0