linux - معنى - باش: انتظر مهلة




windows subsystem for linux (3)

في نص باش، أود أن أفعل شيئا مثل:

app1 &
pidApp1=$!
app2 &
pidApp2=$1

timeout 60 wait $pidApp1 $pidApp2
kill -9 $pidApp1 $pidApp2

إي، إطلاق اثنين من التطبيقات في الخلفية، ومنحهم 60 ثانية لإكمال عملهم. ثم، إذا لم ينتهوا خلال تلك الفترة، قتلهم.

للأسف، ما سبق لا يعمل، منذ timeout هو قابل للتنفيذ، في حين wait هو أمر قذيفة. حاولت تغييره إلى:

timeout 60 bash -c wait $pidApp1 $pidApp2

ولكن هذا لا يزال لا يعمل، لأن wait لا يمكن إلا أن يسمى على بيد أطلقت داخل نفس قذيفة.

أيه أفكار؟


وفيما يلي نسخة مبسطة من إجابة آرون ديغولا، والتي تستخدم خدعة kill -0 التي يتركها آرون ديغولا في تعليق:

app &
pidApp=$!
( sleep 60 ; echo 'timeout'; kill $pidApp ) &
killerPid=$!

wait $pidApp
kill -0 $killerPid && kill $killerPid

في حالتي، أردت أن تكون على حد سواء set -e -x آمنة وعودة رمز الحالة، لذلك كنت:

set -e -x
app &
pidApp=$!
( sleep 45 ; echo 'timeout'; kill $pidApp ) &
killerPid=$!

wait $pidApp
status=$?
(kill -0 $killerPid && kill $killerPid) || true

exit $status

حالة الخروج من 143 يشير سيغترم، من المؤكد تقريبا من مهلة لدينا.


كل من المثال الخاص بك والإجابة المقبولة معقدة للغاية، لماذا لا تستخدم timeout فقط لأن هذا هو بالضبط حالة استخدامها؟ الأمر timeout حتى لديه خيار يحمل في ثناياه عوامل ( -k ) لإرسال SIGKILL بعد إرسال إشارة أولية لإنهاء الأمر ( SIGTERM افتراضيا) إذا كان الأمر لا يزال قيد التشغيل بعد إرسال إشارة أولية (انظر man timeout ).

إذا كان السيناريو لا يتطلب بالضرورة wait واستئناف تدفق السيطرة بعد الانتظار انها مجرد مسألة

timeout -k 60s 60s app1 &
timeout -k 60s 60s app2 &
# [...]

ومع ذلك، إذا كان الأمر كذلك، فسيكون ذلك سهلا من خلال حفظ timeout تعريف بيد timeout بدلا من ذلك:

pids=()
timeout -k 60s 60s app1 &
pids+=($!)
timeout -k 60s 60s app2 &
pids+=($!)
wait "${pids[@]}"
# [...]

على سبيل المثال

$ cat t.sh
#!/bin/bash

echo "$(date +%H:%M:%S): start"
pids=()
timeout 10 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 1 terminated successfully"' &
pids+=($!)
timeout 2 bash -c 'sleep 5; echo "$(date +%H:%M:%S): job 2 terminated successfully"' &
pids+=($!)
wait "${pids[@]}"
echo "$(date +%H:%M:%S): done waiting. both jobs terminated on their own or via timeout; resuming script"

.

$ ./t.sh
08:59:42: start
08:59:47: job 1 terminated successfully
08:59:47: done waiting. both jobs terminated on their own or via timeout; resuming script

كتابة بيدس للملفات وبدء تطبيقات مثل هذا:

pidFile=...
( app ; rm $pidFile ; ) &
pid=$!
echo $pid > $pidFile
( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) &
killerPid=$!

wait $pid
kill $killerPid

وهذا من شأنه أن يخلق عملية أخرى تنام لمدة مهلة ويقتل العملية إذا لم تكتمل حتى الآن.

إذا اكملت العملية بشكل أسرع، يتم حذف ملف بيد ويتم إنهاء عملية القاتل.

killChildrenOf هو السيناريو الذي يجلب جميع العمليات ويقتل جميع الأطفال من بيد معينة. انظر إجابات هذا السؤال لطرق مختلفة لتنفيذ هذه الوظيفة: أفضل طريقة لقتل جميع العمليات الطفل

إذا كنت ترغب في خطوة خارج باش، هل يمكن أن يكتب بيد و مهلة في دليل ومشاهدة هذا الدليل. كل دقيقة أو نحو ذلك، قراءة الإدخالات والتحقق من العمليات التي لا تزال حولها وما إذا كانت قد انتهت المهلة.

إديت إذا كنت تريد أن تعرف ما إذا كانت العملية قد توفي بنجاح، يمكنك استخدام kill -0 $pid

EDIT2 أو يمكنك محاولة مجموعات العملية. وقال كيفينارب : للحصول على بجيد ل بيد (146322):

ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }'

في حالتي: 145974. ثم بجيد يمكن استخدامها مع خيار خاص من قتل لإنهاء جميع العمليات في مجموعة: kill -- -145974





shell