باش: ابدأ أوامر متعددة بالسلاسل في الخلفية
-
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
سيعطيك الخيار إحصائيات تفاصيل العملية التي تحدث. لذلك يمكننا أن نعرف كيف تم الانتهاء من العملية وإلى متى ستستغرق الانتهاء.