我在看https://stackoverflow.com/a/10225050/1737158
在同一个Q中,timeout
命令有一个答案,但并不是所有操作系统,所以我想避免它。
我尝试做的是:
demo="$(top)" &
TASK_PID=$!
sleep 3
echo "TASK_PID: $TASK_PID"
echo "demo: $demo"
我期望在$ demo变量中没有任何内容,而top
命令永远不会结束。
现在我得到一个空的结果。哪个是“可以接受的”,但是当我重新使用与应该返回值的命令相同的东西时,我仍然得到一个空结果,这是不行的。 E.g:
demo="$(uptime)" &
TASK_PID=$!
sleep 3
echo "TASK_PID: $TASK_PID"
echo "demo: $demo"
这应该返回正常运行时间结果,但事实并非如此。我也尝试通过TASK_PID杀死进程,但我总是得到。如果命令失败,我希望以某种方式捕获stderr。它可以是不同的变量,但必须被捕获而不会被泄露出来。
答案 0 :(得分:1)
var=$(cmd) &
让我们首先注意bash
中的simple command具有以下形式:
[variable assignments] [command] [redirections]
例如
$ demo=$(echo 313) declare -p demo
declare -x demo="313"
根据manual:
[..]每个变量赋值中
=
之后的文本在分配给变量之前经历了波浪扩展,参数扩展,命令替换,算术扩展和引用删除。
此外,在展开上面的[command]
之后,第一个单词被视为命令的名称,但是:
如果没有命令名称,变量赋值会影响当前的shell环境。否则,变量将添加到已执行命令的环境中,不会影响当前的shell环境。
因此,正如预期的那样,当运行demo=$(cmd)
时,$(..)
命令替换的结果将分配给当前shell中的demo
变量 。 / p>
需要注意的另一点是与背景运算符&
相关。它在所谓的lists上运行,它是一个或多个pipelines的序列。也:
如果控制操作员
&
终止命令,则shell 在子shell中异步执行命令 。这称为在后台执行命令 。
最后,当你说:
$ demo=$(top) &
# ^^^^^^^^^^^ simple command, consisting ONLY of variable assignment
这个简单的命令在子shell中执行(称之为s1
),其中$(top)
在另一个子shell中执行(称之为s2
),此命令替换的结果是分配给shell demo
内的变量s1
。由于没有给出命令,在赋值变量后,s1
终止,但父shell永远不会接收在子(s1
)中设置的变量。
如果您正在寻找以异步方式与流程进行通信的可靠方式,则可以考虑bash
中的coprocesses或其他POSIX环境中的named pipes (FIFO)。
协同处理设置更简单,因为coproc
会为您设置管道,但请注意,如果在写入任何输出之前终止进程,您可能无法可靠地读取它们。
#!/bin/bash
coproc top -b -n3
cat <&${COPROC[0]}
FIFO 设置看起来像这样:
#!/bin/bash
# fifo setup/clean-up
tmp=$(mktemp -td)
mkfifo "$tmp/out"
trap 'rm -rf "$tmp"' EXIT
# bg job, terminates after 3s
top -b >"$tmp/out" -n3 &
# read the output
cat "$tmp/out"
但请注意,如果在阻止模式下打开FIFO,则在有人打开它进行读取(并开始读取)之前,编写器将无法写入。
您将如何终止后台进程取决于您使用的设置,但对于上面的简单coproc
案例:
#!/bin/bash
coproc top -b
sleep 3
kill -INT "$COPROC_PID"
cat <&${COPROC[0]}