在 bash 后台运行时的内部 for 循环会产生新的 bash 进程

Man*_*hat 4 bash pipe background-process for

我正在执行下面的脚本

LOGDIR=~/curl_result_$(date |tr ' :' '_')

mkdir $LOGDIR

for THREADNO in $(seq 20)
do
for REQNO in $(seq 20)
do
 time curl --verbose -sS  http://dummy.restapiexample.com/api/v1/create --trace-ascii ${LOGDIR}/trace_${THREADNO}_${REQNO} -d @- <<EOF >> ${LOGDIR}/response_${THREADNO} 2>&1
 {"name":"emp_${THREADNO}_${REQNO}_$(date |tr ' :' '_')","salary":"$(echo $RANDOM%100000|bc)","age":"$(echo $RANDOM%100000|bc)"}
EOF
echo -e "\n-------------------------------" >> ${LOGDIR}/response_${THREADNO}
done 2>&1 | grep real > $LOGDIR/timing_${THREADNO} &
done
Run Code Online (Sandbox Code Playgroud)

一段时间后,如果我检查没有 bash 进程,它会显示 20(不是 1 或 21)

ps|grep bash|wc -l
Run Code Online (Sandbox Code Playgroud)

问题是由于我没有使用方括号“()”来包围内循环,所以不应该产生新的 shell 进程。我想避免在 CPU 使用率接近 100% 时创建新的 shell。我不知道这是否重要,但我正在使用 Cygwin。

Mic*_*mer 7

因为您已将循环通过管道传输到 中grep,所以它必须在子shell 中运行。Bash手册中提到这一点:

管道中的每个命令都在其自己的子 shell 中执行,这是一个单独的进程(请参阅命令执行环境

这是可能避免与lastpipe外壳选项最终在管道命令,而不是任何其他人。在任何情况下,您都将整个管道置于后台,这创建了一个子外壳。

没有办法解决这个问题。您正在做的事情本质上确实需要单独的 shell 进程才能工作:即使忽略管道,创建后台进程也需要创建一个进程。

如果您的问题是 CPU 使用率,那是由一次运行所有内容引起的。如果删除&之后的grep,所有命令将按顺序运行,而不是同时运行。仍然会创建子shell(用于管道),但在这种情况下,这些本身并不是主要问题。如果您需要它们同时运行,增加的 CPU 使用率是您选择的权衡。