在脚本中你没有工作控制(并试图打开它是愚蠢的)
这是我第一次听到这个,而且我仔细考虑了关于工作控制的bash.info部分(第7章),没有提到这些断言中的任何一个.[ 更新:手册页稍好一些,提到'典型'使用,默认设置和终端I/O,但没有真正的理由说明为什么作业控制对于脚本来说特别不明智.
那么为什么基于脚本的作业控制不起作用,又是什么使它成为一种不好的做法(又名"愚蠢")?
编辑:有问题的脚本启动一个后台进程,启动第二后台进程,然后试图将所述第一进程返回到前景,以便它具有普通端子I/O(如如果直接运行),然后可以被重定向从在剧本之外.不能这样做到后台进程.
正如另一个问题的已接受答案所指出的,存在其他脚本可以在不尝试作业控制的情况下解决该特定问题.精细.lambasted脚本使用硬编码的作业号 - 显然很糟糕.但我试图了解工作控制是否是一种根本注定失败的方法.它似乎仍然可以工作......
vla*_*adr 42
他的意思是默认情况下,作业控制在非交互模式下(即在脚本中)关闭.
从bash手册页:
JOB CONTROL
Job control refers to the ability to selectively stop (suspend)
the execution of processes and continue (resume) their execution at a
later point.
A user typically employs this facility via an interactive interface
supplied jointly by the system’s terminal driver and bash.
Run Code Online (Sandbox Code Playgroud)
和
set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
...
-m Monitor mode. Job control is enabled. This option is on by
default for interactive shells on systems that support it (see
JOB CONTROL above). Background processes run in a separate
process group and a line containing their exit status is
printed upon their completion.
Run Code Online (Sandbox Code Playgroud)
当他说"愚蠢"时,他的意思不仅仅是:
UPDATE
回答您的评论:是的,没有人会阻止您在bash脚本中使用作业控制 - 没有强制禁用的情况 set -m(即是的,如果您需要,脚本中的作业控制将起作用.)请记住最后,特别是在脚本编写方面,总是有不止一种方法可以对猫进行换肤,但有些方法更便携,更可靠,更容易处理错误情况,解析输出等等.
您的特定情况可能会或可能不会保证与lhunath(和其他用户)认为"最佳实践"不同的方式.
And*_*ler 32
使用bg和进行作业控制fg仅在交互式shell中有用.但&结合使用wait在脚本中也很有用.
在多处理器系统上,生成后台作业可以极大地提高脚本的性能,例如在构建脚本中,您希望每个CPU启动至少一个编译器,或者使用ImageMagick工具并行处理图像等.
以下示例最多运行8个并行gcc来编译数组中的所有源文件:
#!bash
...
for ((i = 0, end=${#sourcefiles[@]}; i < end;)); do
for ((cpu_num = 0; cpu_num < 8; cpu_num++, i++)); do
if ((i < end)); then gcc ${sourcefiles[$i]} & fi
done
wait
done
Run Code Online (Sandbox Code Playgroud)
没有什么"愚蠢"的.但是您将需要该wait命令,该命令在脚本继续之前等待所有后台作业.最后一个后台作业的PID存储在$!变量中,因此您也可以wait ${!}.还要注意nice命令.
有时这样的代码在makefile中很有用:
buildall:
for cpp_file in *.cpp; do gcc -c $$cpp_file & done; wait
Run Code Online (Sandbox Code Playgroud)
这比控制更精细make -j.
注意,这&是一个行终止符,如;(command& 不写command&;).
希望这可以帮助.
只有在运行交互式shell时,作业控制才有用,即,您知道stdin和stdout已连接到终端设备(Linux上的/ dev/pts/*).然后,在前景上有东西,在背景上有其他东西等是有意义的.
另一方面,脚本没有这样的保证.脚本可以变为可执行文件,并且无需连接任何终端即可运行.在这种情况下,拥有前台或后台进程是没有意义的.
但是,您可以在后台以非交互方式运行其他命令(将"&"附加到命令行)并使用它来捕获它们的PID $!.然后你用它kill来杀死或暂停它们(在终端上模拟Ctrl-C或Ctrl-Z,它是shell是交互式的).您也可以使用wait(而不是fg)等待后台进程完成.
小智 5
在脚本中打开作业控制以在SIGCHLD上设置陷阱可能很有用.手册中的JOB CONTROL部分说:
当作业改变状态时,shell立即学习.通常,bash会在报告作业状态更改之前等待打印提示,以免中断任何其他输出.如果启用了set builtin命令的-b选项,bash会立即报告此类更改. SIGCHLD上的任何陷阱都会针对退出的每个子进行执行.
(重点是我的)
以下面的脚本为例:
dualbus@debian:~$ cat children.bash
#!/bin/bash
set -m
count=0 limit=3
trap 'counter && { job & }' CHLD
job() {
local amount=$((RANDOM % 8))
echo "sleeping $amount seconds"
sleep "$amount"
}
counter() {
((count++ < limit))
}
counter && { job & }
wait
dualbus@debian:~$ chmod +x children.bash
dualbus@debian:~$ ./children.bash
sleeping 6 seconds
sleeping 0 seconds
sleeping 7 seconds
Run Code Online (Sandbox Code Playgroud)
注意:从bash 4.3开始,CHLD陷阱似乎被打破了
在bash 4.3中,您可以使用'wait -n'来实现相同的功能,但是:
dualbus@debian:~$ cat waitn.bash
#!/home/dualbus/local/bin/bash
count=0 limit=3
trap 'kill "$pid"; exit' INT
job() {
local amount=$((RANDOM % 8))
echo "sleeping $amount seconds"
sleep "$amount"
}
for ((i=0; i<limit; i++)); do
((i>0)) && wait -n; job & pid=$!
done
dualbus@debian:~$ chmod +x waitn.bash
dualbus@debian:~$ ./waitn.bash
sleeping 3 seconds
sleeping 0 seconds
sleeping 5 seconds
Run Code Online (Sandbox Code Playgroud)
您可以争辩说还有其他方法可以通过更便携的方式执行此操作,即没有CHLD或等待-n:
dualbus@debian:~$ cat portable.sh
#!/bin/sh
count=0 limit=3
trap 'counter && { brand; job & }; wait' USR1
unset RANDOM; rseed=123459876$$
brand() {
[ "$rseed" -eq 0 ] && rseed=123459876
h=$((rseed / 127773))
l=$((rseed % 127773))
rseed=$((16807 * l - 2836 * h))
RANDOM=$((rseed & 32767))
}
job() {
amount=$((RANDOM % 8))
echo "sleeping $amount seconds"
sleep "$amount"
kill -USR1 "$$"
}
counter() {
[ "$count" -lt "$limit" ]; ret=$?
count=$((count+1))
return "$ret"
}
counter && { brand; job & }
wait
dualbus@debian:~$ chmod +x portable.sh
dualbus@debian:~$ ./portable.sh
sleeping 2 seconds
sleeping 5 seconds
sleeping 6 seconds
Run Code Online (Sandbox Code Playgroud)
因此,总而言之,set -m 在脚本中没有那么有用,因为它为脚本带来的唯一有趣的功能是能够与SIGCHLD一起工作.还有其他方法可以实现相同的更短(等待-n)或更便携(自己发送信号).