باش: ابدأ أوامر متعددة بالسلاسل في الخلفية

StackOverflow https://stackoverflow.com/questions/161252

  •  03-07-2019
  •  | 
  •  

سؤال

أحاول تشغيل بعض الأوامر في Paralel ، في الخلفية ، باستخدام Bash. هذا ما أحاول القيام به:

forloop {
  //this part is actually written in perl
  //call command sequence
  print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}

يولد الجزء بين backticks (``) قذيفة جديدة وتنفذ الأوامر المتتالية. الشيء هو أن التحكم في البرنامج الأصلي يعود فقط بعد تنفيذ الأمر الأخير. أرغب في تنفيذ البيان بأكمله في الخلفية (لا أتوقع أي قيم إخراج/إرجاع) وأود أن تستمر الحلقة.

لن ينتهي برنامج الاتصال (الذي يحتوي على الحلقة) حتى تنتهي جميع القذائف الممتدة.

يمكنني استخدام مؤشرات الترابط في بيرل لتفرخ مؤشرات ترابط مختلفة تسمي قذائف مختلفة ، لكنها تبدو مبالغة ...

هل يمكنني بدء قذيفة ، وإعطائها مجموعة من الأوامر وأخبرها بالذهاب إلى الخلفية؟

هل كانت مفيدة؟

المحلول

لم أختبر هذا ولكن ماذا عن

print `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;

أقواس يعني التنفيذ في فرعي ولكن هذا لا ينبغي أن يضر.

نصائح أخرى

شكرا هيو ، هذا فعل ذلك:

adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
adrianp@frost:~$ stopped

[1]+  Done                    ( echo "started"; sleep 15; echo "stopped" )
adrianp@frost:~$ 

الأفكار الأخرى لا تعمل لأنها تبدأ كل أمر في الخلفية ، وليس تسلسل الأوامر (وهو أمر مهم في حالتي!).

شكرا مرة اخرى!

طريقة أخرى هي استخدام بناء الجملة التالي:

{ command1; command2; command3; } &
wait

نلاحظ أن & يذهب في نهاية مجموعة الأوامر ، وليس بعد كل أمر. يعد Semicolon بعد الأمر النهائي ضروريًا ، وكذلك المساحة بعد القوس الأول وقبل الشريحة النهائية. ال wait في النهاية ، يضمن عدم قتل عملية الوالدين قبل انتهاء عملية الطفل (مجموعة القيادة).

يمكنك أيضًا القيام بأشياء رائعة مثل إعادة التوجيه stderr و stdout:

{ command1; command2; command3; } 2>&2 1>&1 &

مثالك سيبدو مثل:

forloop() {
    { touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end
for command in $commands
do
    "$command" &
done
wait

تديرها ampersand في نهاية الأمر في الخلفية ، و wait ينتظر حتى يتم الانتهاء من مهمة الخلفية.

جافينكاتيل حصلت على الأقرب (لباش ، IMO) ، ولكن كما أشار Mad_ady ، فإنه لن يتعامل مع ملفات "القفل". هذا يجب:

إذا كانت هناك وظائف أخرى معلقة ، انتظر سوف تنتظر هؤلاء أيضا. إذا كنت بحاجة إلى الانتظار فقط النسخ ، يمكنك تجميع تلك pids وانتظر فقط تلك. إذا لم يكن الأمر كذلك ، فيمكنك حذف الأسطر الثلاثة مع "PIDS" ولكنه أكثر عمومية.

بالإضافة إلى ذلك ، أضفت التحقق لتجنب النسخة تمامًا:

pids=
for file in bigfile*
do
    # Skip if file is not newer...
    targ=/destination/$(basename "${file}")
    [ "$targ" -nt "$file" ] && continue

    # Use a lock file:  ".fileN.lock" for each "bigfileN"
    lock=".${file##*/big}.lock"
    ( touch $lock; cp "$file" "$targ"; rm $lock ) &
    pids="$pids $!"
done
wait $pids

بالمناسبة ، يبدو أنك تقوم بنسخ ملفات جديدة إلى مستودع FTP (أو ما شابه). إذا كان الأمر كذلك ، فأنت استطاع فكر في استراتيجية نسخة/إعادة تسمية بدلاً من ملفات القفل (ولكن هذا موضوع آخر).

يسمى المرفق في باش الذي تبحث عنه Compound Commands. انظر صفحة الرجل لمزيد من المعلومات:

الأوامر المركبة أمر مركب هو واحد مما يلي:

   (list) list  is  executed  in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below).  Variable assignments and
          builtin commands that affect the shell's environment do not remain in effect after  the  command  completes.   The
          return status is the exit status of list.

   { list; }
          list  is  simply  executed in the current shell environment.  list must be terminated with a newline or semicolon.
          This is known as a group command.  The return status is the exit status of list.  Note that unlike the metacharac‐
          ters  (  and  ),  {  and  } are reserved words and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from list by whitespace or another shell  metacharac‐
          ter.

هناك آخرون ، لكن هذه هي النوعين الأكثر شيوعًا. الأول ، The Parens ، ستقوم بتشغيل قائمة بالأمر في السلسلة في Subshell ، في حين أن الدعامة الثانية ، The Curly Curly ، ستقوم قائمة بالأوامر في السلسلة في القشرة الحالية.

بارينز

% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013

الأقواس المعقوفة

% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013

قم بتشغيل الأمر باستخدام AT Job:

# date
# jue sep 13 12:43:21 CEST 2012
# at 12:45
warning: commands will be executed using /bin/sh
at> command1
at> command2
at> ...
at> CTRL-d
at> <EOT>
job 20 at Thu Sep 13 12:45:00 2012

سيتم إرسال النتيجة إلى حسابك عن طريق البريد.

لقد تعثرت على هذا الموضوع هنا وقررت وضع مقتطف رمز لتفرخ البيانات بالسلاسل كوظائف خلفية. لقد اختبرت هذا على Bash for Linux و KSH لـ IBM AIX و Ambox's Ash for Android ، لذلك أعتقد أنه من الآمن قول أنه يعمل على أي قذيفة تشبه بورن.

processes=0;
for X in `seq 0 10`; do
   let processes+=1;
   { { echo Job $processes; sleep 3; echo End of job $processes; } & };
   if [[ $processes -eq 5 ]]; then
      wait;
      processes=0;
   fi;
done;

يدير هذا الرمز عددًا من وظائف الخلفية إلى حد معين من الوظائف المتزامنة. يمكنك استخدام هذا ، على سبيل المثال ، لإعادة ضغط الكثير من ملفات Gzipped مع xz دون وجود حفنة ضخمة من xz تتناول العمليات ذاكرتك بالكامل وجعل جهاز الكمبيوتر الخاص بك يرمي: في هذه الحالة ، تستخدم * كما forقائمة ووظيفة الدُفعات ستكون gzip -cd "$X" | xz -9c > "${X%.gz}.xz".

قم بتشغيل الأوامر في Subshell:

(command1 ; command2 ; command3) &

حاول وضع الأوامر في أقواس مجعد مع & s ، مثل هذا:

{command1 & ; command2 & ; command3 & ; }

هذا لا ينشئ قشرة فرعية ، ولكنه ينفذ مجموعة الأوامر في الخلفية.

HTH

لا أعرف لماذا لا أحد يرد بالحل المناسب:

my @children;
for (...) {
    ...
    my $child = fork;
    exec "touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;" if $child == 0;
    push @children, $child;
}
# and if you want to wait for them to finish,
waitpid($_) for @children;

هذا يجعل بيرل يولد الأطفال لتشغيل كل أمر ، ويسمح لك بالانتظار حتى يكتمل جميع الأطفال قبل المتابعة.

على فكرة،

print `some command`

و

system "some command"

إخراج نفس المحتويات إلى stdout ، ولكن الأول له النفقات العامة العليا ، حيث يتعين على بيرل التقاط كل شيء "some command"إخراج

forking في حلقة:

for i in x; do ((a; b; c;)&); done

مثال:

for i in 500 300 100; do ((printf "Start $i: "; date; dd if=/dev/zero of=testfile_$i bs=1m count=$i 2>/dev/null; printf "End $i: "; date;)&) && sleep 1; done

فقط في حال كان شخص ما لا يزال مهتمًا ، يمكنك القيام بذلك دون استدعاء Subshell مثل هذا:

print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;

يمكنك استخدام GNU parallel أمر لتشغيل الوظائف بالتوازي. إنها أكثر أمانًا أسرع.

أظن أنك تحاول نسخ عدة ملفات كبيرة من مصدر إلى وجهة. ولهذا يمكنك القيام بذلك بالتوازي مع البيان أدناه.

$ ls *|parallel -kj0 --eta 'cp {} /tmp/destination'

كما استخدمنا -j0 الخيار ، سيتم نسخ جميع الملفات بالتوازي. في حالة حاجة إلى تقليل عدد العملية الموازية ، يمكنك استخدامها -j<n> أين <n> هو عدد العملية الموازية التي سيتم تنفيذها.

سيقوم التوازي أيضًا بجمع إخراج العملية والإبلاغ عنها بطريقة متتابعة (مع -k الخيار) ما هي آلية التحكم في الوظائف الأخرى التي لا تستطيع القيام بها.

--eta سيعطيك الخيار إحصائيات تفاصيل العملية التي تحدث. لذلك يمكننا أن نعرف كيف تم الانتهاء من العملية وإلى متى ستستغرق الانتهاء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top