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中执行此操作?
答案 0 :(得分:14)
这是另一种方法,这是另一种方式,它可以保证单独的答案。我认为这个方法是无子shell和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:~$ bar 1>&3
ubuntu@ubuntu:~$ read -u3 a
ubuntu@ubuntu:~$ echo $a
0 8215
ubuntu@ubuntu:~$ exec 3>&-
ubuntu@ubuntu:~$ rm /tmp/myfifo
ubuntu@ubuntu:~$
这里的技巧是使用exec
以FD读写模式打开FIFO,这似乎具有使FIFO无阻塞的副作用。然后,您可以将命令重定向到FD而不阻塞它,然后读取FD。
请注意,FIFO将是一个有限大小的缓冲区,可能大约为4K,所以如果你的命令产生的输出多于此值,它将最终再次阻塞。
答案 1 :(得分:4)
这是我能想到的 - 它有点乱,但foo
在顶层shell上下文中运行,其输出在顶层shell的变量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 "%s\n" "${buf[$i]}"
done > /tmp/fifo2
} &
foo > /tmp/fifo1
read a < /tmp/fifo2
echo $a
rm /tmp/fifo{1,2}
这当然假设有两件事:
我测试了这个版本以适用于bash个版本:
我不确定bash 4.x中的mapfile
方法是否符合您的要求,因为进程替换<()
创建了一个全新的bash进程(尽管不是bash进程中的bash子shell) ):
$ bar () { echo "$BASH_SUBSHELL $BASHPID"; }
$ bar
0 2636
$ mapfile -t bar_output < <(bar)
$ echo ${bar_output[0]}
0 60780
$
因此虽然$BASH_SUBSHELL
在这里为0,但这是因为它在流程替换中位于新shell进程60780的顶层。
答案 2 :(得分:1)
最简单的方法是删除函数并直接传递变量,例如:
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&gt; 4):
mapfile -t foo_output < <(foo)
readarray -t foo_output < <(foo)
然后将输出转换回数组:
foo_arr=($foo_output)
subshell_depth=${foo_arr[0]} # should be 0
答案 3 :(得分:1)
在查看如何将任何“打印”命令的输出捕获到变量中时,这个问题经常出现。所以对于任何看起来都是可能的(自bash v3.1.0起):
printf -v VARIABLE_NAME "whatever you need here: %s" $ID
如果你调整脚本的速度,那么你可以使用在函数末尾设置一些全局变量的模式而不是“回显”它 - 小心使用它,它有时被批评为导致难以维护的代码。 / p>