[英]Trap and exit big shell script with background processes
我有 2 個 shell 腳本,其中包含 ffmpeg 個命令(command1.sh 和 command2.sh)。 command2.sh 有大約 500 個 ffmpeg 命令,這些命令用“;”一個接一個地觸發,而 command1.sh 處理音頻 ffmpeg 命令。
主要問題:殺死整個腳本需要太多時間,它占用了我執行另一個腳本所需的 CPU 能力 1-2 分鍾,所以我白白失去了 CPU 能力,因為我無法立即殺死它。
代碼:我有init.sh包含:
trap 'print TERM received;exit' 15
chmod +x command1.sh;
chmod +x command2.sh;
./command1.sh & ./command2.sh
所以它在后台觸發。
然后我執行pkill init.sh並捕獲 shell陷阱並退出shell 腳本但我得到 exitCode: 1, failed: true 並且后台命令仍然執行 1 分鍾,直到它們被另一個 kill ${pid我在 pkill 之后執行。
chmod +x
在這里沒用。 您完全可以改為運行sh command1.sh &
。就像是:
#!/bin/sh
for cmd in ./command1.sh ./command2.sh;do
exec $cmd &
PIDS="$PIDS $!"
done
trap "kill $PIDS;exit" 15
wait
當然,在for cmd in
和;do
之間,您可以放置任意數量的commandXX.sh
(只要您將行長度保持在已安裝操作系統支持的最大長度)
這是一個快速的bash測試腳本,它在 2.0 到 12.99 秒之間隨機休眠,然后打印done.
退出前:
#!/bin/bash
declare -i toSleep
case $1 in '' | *[!0-9]* ) toSleep='RANDOM%10+2' ;; * ) toSleep=$1 ;; esac
exec {dummy}<> <(:)
read -t $toSleep.$RANDOM -u $dummy _
echo done.
我已將其保存到command1.sh
, chmod +x..
並鏈接到command2.sh
...
#!/bin/sh
for cmd in "$@";do
exec $cmd &
PIDS="$PIDS $!"
done
printf "You have to: kill -TERM %d\nto end %d tasks: %s\n" \
$$ $(echo $PIDS|wc -w) "$PIDS"
trap "kill $PIDS;echo 'Process $$ killed.';exit" 15
wait
echo "Process $$ running $@ ended normally"
您可以將此shell腳本保存到名為simpleParallel.sh
的文件中,例如,然后:
chmod +x simpleParallel.sh
./simpleParallel.sh ./command1.sh ./command2.sh
You have to: kill -TERM 741297
to end 2 tasks: 741298 741299
然后,如果您從其他地方kill -TERM 741297
,
Process 741297 killed.
但如果你不這樣做,你可能會讀到這樣的東西:
./simpleParallel.sh ./command1.sh ./command2.sh
You have to: kill -TERM 741968
to end 2 tasks: 741969 741970
done.
done.
Process 741968 running ./command1.sh ./command2.sh ended normally
注意:如果您在一個進程已完成時發送 kill 命令,您可能會看到如下錯誤消息:
./simpleParallel.sh: 1: kill: No such process
看bash版本可以避免這個bug。
在運行./simpleParallel.sh
之前,您可以不帶參數運行tty
:
tty
/dev/pts/2
然后在一個新的免費 window 中,你可以運行:
watch ps --tty pts/2
同時再次使用另一個 window 運行kill
命令。
在最近的bash下,有很多特色。
$EPOCHREALTIME
變量,它以微秒粒度擴展為自 Unix 紀元以來的秒數。wait
有了一個新的[-p VARNAME]
選項,它存儲了wait -n
或wait
沒有 arguments 返回的PID
。我的腳本可能變成:
#!/bin/bash
declare -A PIDS ENDED
started=$EPOCHREALTIME
for cmd; do
exec "$cmd" &
PIDS["$cmd"]=$!
CMDS[$!]="$cmd"
done
printf "You have to: kill -TERM %d\nto end %d tasks: %s\n" \
$$ ${#PIDS[@]} "${PIDS[*]}"
trapExit(){
kill "${PIDS[@]}"
printf 'Process %s + %d task killed: %s\n' $$ ${#PIDS[@]} "${!PIDS[*]}"
showDone
exit 1
}
trap trapExit 15
showDone() {
for cmd in "${!ENDED[@]}";do
read -r elap < <(bc -l <<<"${ENDED["$cmd"]}-$started")
printf "Elapsed: %.4f sec for %s\n" "$elap" "$cmd"
done
}
while ((${#PIDS[@]}));do if wait -n -p pid ;then
printf "Process %d done (%s).\n" "$pid" "${CMDS[pid]}"
ENDED["${CMDS[pid]}"]=$EPOCHREALTIME
unset PIDS["${CMDS[pid]}"] CMDS[pid]
fi; done
echo "Process $$ running $* ended normally"
showDone
Output 可能看起來像:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1309816
to end 2 tasks: 1309817 1309818
done.
Process 1309817 done (./command1.sh).
done.
Process 1309818 done (./command2.sh).
Process 1309816 running ./command1.sh ./command2.sh ended normally
Elapsed: 3.1644 sec for ./command1.sh
Elapsed: 4.2488 sec for ./command2.sh
或者
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1310031
to end 2 tasks: 1310032 1310033
done.
Process 1310033 done (./command2.sh).
done.
Process 1310032 done (./command1.sh).
Process 1310031 running ./command1.sh ./command2.sh ended normally
Elapsed: 9.1868 sec for ./command1.sh
Elapsed: 3.2310 sec for ./command2.sh
如果你早點kill
了他們:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294577
to end 2 tasks: 1294578 1294579
Process 1294577 + 2 task killed: ./command1.sh ./command2.sh
如果你稍后kill
了他們:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294958
to end 2 tasks: 1294959 1294960
done.
Process 1294959 done (./command1.sh).
Process 1294958 + 1 task killed: ./command2.sh
Elapsed: 3.1779 sec for ./command1.sh
或者
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294971
to end 2 tasks: 1294972 1294973
done.
Process 1294973 done (./command2.sh).
Process 1294971 + 1 task killed: ./command1.sh
Elapsed: 6.9344 sec for ./command2.sh
並且沒有關於試圖殺死不存在的 pid 的錯誤消息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.