বাশে একটি নির্দিষ্ট সময়সীমা শেষে কোনও শিশু প্রক্রিয়া কীভাবে হত্যা করা যায়?


178

আমার একটি বাশ স্ক্রিপ্ট রয়েছে যা একটি শিশু প্রক্রিয়া চালু করে যা সময়ে সময়ে ক্র্যাশ হয় (প্রকৃতপক্ষে স্তব্ধ হয়ে যায়) এবং কোনও আপাত কারণ ছাড়াই (বন্ধ উত্স, তাই আমি এটি সম্পর্কে অনেক কিছুই করতে পারি না)। ফলস্বরূপ, আমি নির্ধারিত সময়ের জন্য এই প্রক্রিয়াটি চালু করতে সক্ষম হতে চাই এবং নির্দিষ্ট সময়ের পরে সফলভাবে ফিরে না আসলে এটি মেরে ফেলতে চাই।

বাশ ব্যবহার করে এটি অর্জনের জন্য কি একটি সহজ এবং শক্তিশালী উপায় আছে?

পিএস: যদি এই প্রশ্নটি সার্ভারফল্ট বা সুপারভাইজারের পক্ষে আরও উপযুক্ত suited



এখানে খুব সম্পূর্ণ প্রতিক্রিয়া: stackoverflow.com/a/58873049/2635443
Orsiris ডি জং

উত্তর:


260

( যেমনটিতে দেখা গেছে: বেস এফএকিউ এন্ট্রি # 68: "আমি কীভাবে কোনও কমান্ড চালাব এবং এন সেকেন্ডের পরে এটি বাতিল করতে হবে?" ))

আপনি যদি কিছু ডাউনলোড করতে আপত্তি না করেন তবে timeout( sudo apt-get install timeout) ব্যবহার করুন এবং এটি ব্যবহার করুন: (বেশিরভাগ সিস্টেমে এটি ইতিমধ্যে ইনস্টল করা হয়েছে অন্যথায় ব্যবহার করুন sudo apt-get install coreutils)

timeout 10 ping www.goooooogle.com

আপনি যদি কিছু ডাউনলোড করতে না চান, তাহলে অভ্যন্তরীণভাবে যা শেষ হবে তা করুন:

( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec ping www.goooooogle.com )

আপনি দীর্ঘ বাশ কোডের জন্য একটি সময়সীমা করতে চান এমন ক্ষেত্রে দ্বিতীয় বিকল্পটি ব্যবহার করুন:

( cmdpid=$BASHPID; 
    (sleep 10; kill $cmdpid) \
   & while ! ping -w 1 www.goooooogle.com 
     do 
         echo crap; 
     done )

8
অন্য কেউ যদি আমি কী করে তা ভেবে অবাক হয় সে ক্ষেত্রে Re Ignacio এর জবাব: কলিং শেলটির cmdpid=$BASHPIDপিডটি গ্রহণ করবে না তবে (প্রথম) সাবশেল যা শুরু হয়েছিল । ... জিনিস পটভূমিতে 10 সেকেন্ড অপেক্ষা করুন এবং প্রথম subshell যা, হত্যাকারী subshell প্রক্রিয়া চালু করার পর, তার কাজের চাপ চালানো আয় হত্যা করার প্রথম subshell মধ্যে দ্বিতীয়বার subshell আহ্বান ...()(sleep
jamadagni

17
timeoutজিএনইউ কোর্টিলের অংশ, তাই ইতিমধ্যে সমস্ত জিএনইউ সিস্টেমে ইনস্টল করা উচিত।
সমীর

1
@ সমীর: কেবল 8 সংস্করণ অনুসারে
Ignacio Vazquez-

3
আমি এ সম্পর্কে 100% নিশ্চিত নই, তবে যতদূর জানি (এবং আমার ম্যানপেজ আমাকে timeoutযা বলেছিল তা এখন ) কোর্টিলগুলির অংশ।
benaryorg

5
এই আদেশটি 'তাড়াতাড়ি শেষ' হয় না। এটি সর্বদা সময়সীমায় প্রক্রিয়াটিকে মেরে ফেলবে - তবে সময়টি শেষ না হওয়া অবস্থায় এটি পরিচালনা করবে না।
হক্কে

28
# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) &

অথবা প্রস্থান কোডগুলি পেতে:

# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) & waiter=$!
# wait on our worker process and return the exitcode
exitcode=$(wait $pid && echo $?)
# kill the waiter subshell, if it still runs
kill -9 $waiter 2>/dev/null
# 0 if we killed the waiter, cause that means the process finished before the waiter
finished_gracefully=$?

8
kill -9কোনও প্রক্রিয়া প্রথমে প্রক্রিয়া করতে পারে এমন সিগন্যালের চেষ্টা করার আগে আপনার ব্যবহার করা উচিত নয় ।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

সত্য, আমি তবেই দ্রুত ঠিক করার জন্য যাচ্ছিলাম এবং কেবল ধরে নিয়েছি যে তিনি তত্ক্ষণাত্ প্রক্রিয়াটি মরে যেতে চান কারণ তিনি বলেছিলেন যে এটি ক্র্যাশ হয়েছে
ড্যান

8
এটি আসলে খুব খারাপ সমাধান। dosmth2 সেকেন্ডের মধ্যে যদি শেষ হয়ে যায়, অন্য প্রক্রিয়াটি পুরানো পিডটি নেবে এবং আপনি নতুনটিকে হত্যা করবেন?
ছাগল

পিআইডি পুনর্ব্যবহারযোগ্যতা সীমাতে পৌঁছে এবং চারপাশে মোড়ানো দ্বারা কাজ করে। অন্য 8 টি প্রসেসের জন্য বাকি 8 সেকেন্ডের মধ্যে পিআইডি পুনরায় ব্যবহার করা খুব সম্ভব নয়, যদি না সিস্টেমটি সম্পূর্ণরূপে হাওয়াইয়ার হয়।
কিটিড্ডোর

13
sleep 999&
t=$!
sleep 10
kill $t

এটি অতিরিক্ত অপেক্ষা করতে বাধ্য করে। যদি বাস্তব নির্দেশ ( sleep 999এখানে) প্রায়শই আরোপিত ঘুমের চেয়ে দ্রুত শেষ করে তবে কী হবে sleep 10? যদি আমি এটি 1 মিনিট, 5 মিনিট পর্যন্ত চান্স দিতে চাই? আমার স্ক্রিপ্টে যদি আমার কাছে এই জাতীয় ঘটনাগুলির একগুচ্ছ থাকে তবে কী হবে :)
it3xl

3

আমারও এই প্রশ্নটি ছিল এবং আমি আরও দুটি জিনিস খুব দরকারী:

  1. ব্যাশে SECONDS পরিবর্তনশীল।
  2. কমান্ড "pgrep"।

সুতরাং আমি কমান্ড লাইনে (OSX 10.9) এ জাতীয় কিছু ব্যবহার করব:

ping www.goooooogle.com & PING_PID=$(pgrep 'ping'); SECONDS=0; while pgrep -q 'ping'; do sleep 0.2; if [ $SECONDS = 10 ]; then kill $PING_PID; fi; done

এটি একটি লুপ হিসাবে, আমি সিপিইউকে শীতল রাখতে একটি "ঘুম 0.2" অন্তর্ভুক্ত করেছি। ;-)

(বিটিডাব্লু: পিং যাইহোক, এটি একটি খারাপ উদাহরণ, আপনি কেবল বিল্ট-ইন "-t" (টাইমআউট) বিকল্পটি ব্যবহার করবেন))


1

ধরে নিই যে আপনার বাচ্চার পিড ট্র্যাক করার জন্য একটি পিড ফাইল রয়েছে (বা সহজেই তৈরি করতে পারেন), আপনি তারপরে একটি স্ক্রিপ্ট তৈরি করতে পারেন যা পিড ফাইলের মোডটাইমটি পরীক্ষা করে এবং প্রয়োজনীয় প্রক্রিয়াটিকে মেরে / রেসপন্স করে। তারপরে আপনার প্রয়োজন অনুযায়ী প্রায় সময়কালে চালানোর জন্য স্ক্রিপ্টটি কেবল ক্রন্টবায় রেখে দিন।

আপনার আরও বিশদ প্রয়োজন হলে আমাকে জানান know যদি এটি আপনার প্রয়োজন অনুসারে এটির মতো না শোনা যায় তবে আপস্টার্টের কী হবে?


1

একটি উপায় হ'ল প্রোগ্রামটি একটি সাব-শেলের মধ্যে চালানো এবং readকমান্ডটি সহ নামযুক্ত পাইপের মাধ্যমে সাবশেলের সাথে যোগাযোগ করা । এইভাবে আপনি প্রক্রিয়াটি চালিত হচ্ছে তার প্রস্থান স্থিতি পরীক্ষা করতে পারেন এবং পাইপের মাধ্যমে এটি আবার যোগাযোগ করতে পারেন।

এখানে yes3 সেকেন্ড পরে কমান্ড সময় নির্ধারণের একটি উদাহরণ রয়েছে । এটি ব্যবহার করে প্রক্রিয়াটির পিআইডি পায় pgrep(সম্ভবত কেবল লিনাক্সে কাজ করে)। পাইপ ব্যবহারে কিছু সমস্যা রয়েছে যে পড়ার জন্য পাইপ খোলার প্রক্রিয়াটি লেখার জন্য না খোলার আগ পর্যন্ত স্তব্ধ হয়ে যাবে এবং বিপরীতভাবে। সুতরাং readকমান্ডটি ফাঁসানো রোধ করতে , আমি ব্যাকগ্রাউন্ড সাবসেলের সাথে পঠনের জন্য পাইপটি "বিবাহিত" করেছি open (পাইপ রিড-রাইট খোলার হিম রোধ করার আরেকটি উপায়, যেমন read -t 5 <>finished.pipe- তবে এটি লিনাক্স ব্যতীত কাজ নাও করতে পারে))

rm -f finished.pipe
mkfifo finished.pipe

{ yes >/dev/null; echo finished >finished.pipe ; } &
SUBSHELL=$!

# Get command PID
while : ; do
    PID=$( pgrep -P $SUBSHELL yes )
    test "$PID" = "" || break
    sleep 1
done

# Open pipe for writing
{ exec 4>finished.pipe ; while : ; do sleep 1000; done } &  

read -t 3 FINISHED <finished.pipe

if [ "$FINISHED" = finished ] ; then
  echo 'Subprocess finished'
else
  echo 'Subprocess timed out'
  kill $PID
fi

rm finished.pipe

0

এখানে একটি প্রয়াস যা কোনও প্রক্রিয়া ইতিমধ্যে বের হয়ে যাওয়ার পরে হত্যা না করার চেষ্টা করে যা একই প্রক্রিয়া আইডি দিয়ে অন্য প্রক্রিয়াটি হত্যার সম্ভাবনা হ্রাস করে (যদিও এই ধরণের ত্রুটি সম্পূর্ণভাবে এড়ানো সম্ভব নয়)।

run_with_timeout ()
{
  t=$1
  shift

  echo "running \"$*\" with timeout $t"

  (
  # first, run process in background
  (exec sh -c "$*") &
  pid=$!
  echo $pid

  # the timeout shell
  (sleep $t ; echo timeout) &
  waiter=$!
  echo $waiter

  # finally, allow process to end naturally
  wait $pid
  echo $?
  ) \
  | (read pid
     read waiter

     if test $waiter != timeout ; then
       read status
     else
       status=timeout
     fi

     # if we timed out, kill the process
     if test $status = timeout ; then
       kill $pid
       exit 99
     else
       # if the program exited normally, kill the waiting shell
       kill $waiter
       exit $status
     fi
  )
}

এর মতো ব্যবহার করুন run_with_timeout 3 sleep 10000যা চালায় sleep 10000তবে এটি 3 সেকেন্ড পরে শেষ হয়।

এটি অন্যান্য উত্তরের মতো যা একটি বিলম্বের পরে শিশু প্রক্রিয়াটি হ'তে ব্যাকগ্রাউন্ড টাইমআউট প্রক্রিয়া ব্যবহার করে। আমি মনে করি এটি ড্যানের বর্ধিত উত্তর হিসাবে প্রায় একই ( https://stackoverflow.com/a/5161274/1351983 ), সময়সীমা শেল বাদে এটি ইতিমধ্যে শেষ হয়ে গেলে হত্যা করা হবে না।

এই প্রোগ্রামটি শেষ হওয়ার পরে, এখনও কয়েকটি দীর্ঘ "ঘুম" প্রক্রিয়া চলবে, তবে সেগুলি নিরীহ হওয়া উচিত।

এটি আমার অন্যান্য উত্তরের চেয়ে ভাল সমাধান হতে পারে কারণ এটি অ-বহনযোগ্য শেল বৈশিষ্ট্যটি read -tব্যবহার করে না এবং ব্যবহার করে না pgrep


মধ্যে পার্থক্য কি (exec sh -c "$*") &এবং sh -c "$*" &? বিশেষত, কেন পরেরটির পরিবর্তে প্রাক্তনটি ব্যবহার করবেন?
জাস্টিন সি

0

আমি এখানে জমা দেওয়া তৃতীয় উত্তর এখানে। এইটি সিগন্যাল বাধাগুলি পরিচালনা করে এবং SIGINTপ্রাপ্তি পটভূমির প্রক্রিয়াগুলি পরিষ্কার করে । এটি কোনও প্রক্রিয়াটির পিআইডি পেতে শীর্ষ প্রশ্নের উত্তরে ব্যবহৃত কৌশল $BASHPIDএবং execকৌশল ব্যবহার করে (এই ক্ষেত্রে একটি অনুরোধে)। এটি সাবসেলের সাথে যোগাযোগ করতে একটি ফিফো ব্যবহার করে যা হত্যা এবং পরিষ্কারের জন্য দায়ী। (এটি আমার দ্বিতীয় উত্তরের পাইপের মতো , তবে নামযুক্ত পাইপ থাকার অর্থ এটিতে সংকেত হ্যান্ডলারটিও লিখতে পারে))$$sh

run_with_timeout ()
{
  t=$1 ; shift

  trap cleanup 2

  F=$$.fifo ; rm -f $F ; mkfifo $F

  # first, run main process in background
  "$@" & pid=$!

  # sleeper process to time out
  ( sh -c "echo \$\$ >$F ; exec sleep $t" ; echo timeout >$F ) &
  read sleeper <$F

  # control shell. read from fifo.
  # final input is "finished".  after that
  # we clean up.  we can get a timeout or a
  # signal first.
  ( exec 0<$F
    while : ; do
      read input
      case $input in
        finished)
          test $sleeper != 0 && kill $sleeper
          rm -f $F
          exit 0
          ;;
        timeout)
          test $pid != 0 && kill $pid
          sleeper=0
          ;;
        signal)
          test $pid != 0 && kill $pid
          ;;
      esac
    done
  ) &

  # wait for process to end
  wait $pid
  status=$?
  echo finished >$F
  return $status
}

cleanup ()
{
  echo signal >$$.fifo
}

আমি যতদূর পারি জাতির পরিস্থিতি এড়াতে চেষ্টা করেছি। তবে, ত্রুটির একটি উত্স আমি মুছে ফেলতে পারি নি যখন প্রক্রিয়াটি সময়সীমা হিসাবে একই সময়ের সমাপ্ত হয়। উদাহরণস্বরূপ, run_with_timeout 2 sleep 2বা run_with_timeout 0 sleep 0। আমার জন্য, পরেরটি একটি ত্রুটি দেয়:

timeout.sh: line 250: kill: (23248) - No such process

যেহেতু এটি এমন একটি প্রক্রিয়াটিকে হত্যা করার চেষ্টা করছে যা ইতিমধ্যে নিজেই উপস্থিত হয়ে গেছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.