باش لا محاصرة المقاطعات خلال رسينك / سوبشيل إكسيك البيانات
سؤال
السياق:
لدي برنامج نصي باش يحتوي على سوبشيل وفخ للخروج بسيودوسينال ، وانها ليست محاصرة بشكل صحيح المقاطعات خلال rsync
.هنا مثال:
#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir
cleanup () {
echo "Cleaning up!"
#do stuff
trap - EXIT
}
trap '{
(cleanup;) | 2>&1 tee -a $logfile
}' EXIT
(
#main script logic, including the following lines:
(exec sleep 10;);
(exec rsync --progress -av --delete $directory1 /var/tmp/$directory2;);
) | 2>&1 tee -a $logfile
trap - EXIT #just in case cleanup isn't called for some reason
فكرة البرنامج النصي هو هذا:يعمل معظم المنطق المهم في غلاف فرعي يتم نقله عبر الأنابيب tee
وإلى ملف السجل ، لذلك أنا لم يكن لديك ل tee
كل سطر واحد من المنطق الرئيسي للحصول على كل شيء تسجيل.كلما ينتهي سوبشيل ، أو يتم إيقاف البرنامج النصي لأي سبب من الأسباب (خروج بسيودوسينال يجب التقاط كل هذه الحالات) ، فإن فخ اعتراض عليه وتشغيل cleanup()
وظيفة ، ومن ثم إزالة الفخ.ال rsync
و sleep
يتم تشغيل الأوامر (النوم هو مجرد مثال) من خلال exec
لمنع إنشاء عمليات الزومبي إذا قمت بقتل البرنامج النصي الأصل أثناء تشغيله ، ويتم لف كل أمر يحتمل أن يكون طويل الأمد في غلاف فرعي خاص به بحيث عندما exec
ينتهي ، لن ينهي البرنامج النصي بأكمله.
المشكلة:
إذا قمت بمقاطعة البرنامج النصي (عبر kill
أو السيطرة + ج) خلال إكسيك / سوبشيل ملفوفة sleep
الأمر ، فخ يعمل بشكل صحيح ، وأرى "تنظيف!"ردد وتسجيل.إذا كنت يقطع البرنامج النصي خلال rsync
القيادة ، أرى rsync
النهاية ، والكتابة rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(544) [sender=3.0.6]
إلى الشاشة ، ثم يموت البرنامج النصي فقط;لا تنظيف ، لا محاصرة.لماذا لا مقاطعة / قتل rsync
تحريك الفخ?
لقد حاولت استخدام --no-detach
التبديل مع رسينك ، لكنه لم يغير أي شيء.لدي باش 4.1.2 ، رسينك 3.0.6 ، سينتوس 6.2.
المحلول
ماذا عن مجرد إعادة توجيه كل الإخراج من النقطة س إلى نقطة الإنطلاق دون الحاجة إلى تكراره في كل مكان والفوضى مع جميع الأصداف الفرعية والمديرين التنفيذيين ...(آمل ألا أفتقد شيئا)
#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir
exec > >(exec tee -a $logfile) 2>&1
cleanup () {
echo "Cleaning up!"
#do stuff
trap - EXIT
}
trap cleanup EXIT
sleep 10
rsync --progress -av --delete $directory1 /var/tmp/$directory2
نصائح أخرى
بالإضافة إلى set -e
, ، أعتقد أنك تريد set -E
:
إذا تم تعيينه ، يتم توريث أي فخ على خطأ من قبل وظائف شل ، واستبدال الأوامر ، والأوامر المنفذة في بيئة قذيفة فرعية.عادة لا يتم توريث فخ الخطأ في مثل هذه الحالات.
بدلا من ذلك ، بدلا من التفاف الأوامر الخاصة بك في سوبشيلز استخدام الأقواس المتعرجة التي سوف لا تزال تعطيك القدرة على إعادة توجيه مخرجات الأمر ولكن سيتم تنفيذها في قذيفة الحالية.
سيتم القبض على إنتيروبت بشكل صحيح إذا قمت بإضافة إنت إلى فخ
trap '{
(cleanup;) | 2>&1 tee -a $logfile
}' EXIT INT
باش محاصرة المقاطعات بشكل صحيح.ومع ذلك ، هذا لا يجيب على السؤال ، لماذا الفخاخ النصي على الخروج إذا sleep
هو إنتيروبتد ، ولا لماذا لا يؤدي على rsync
, ، ولكن يجعل البرنامج النصي يعمل كما هو مفترض.نأمل أن يساعد هذا.
قد يتم تكوين قذيفة للخروج على الخطأ:
bash # enter subshell
set -e
trap "echo woah" EXIT
sleep 4
إذا كنت تقاطع sleep
(^ج) ثم سيخرج الغلاف الفرعي بسبب set -e
و طباعة woah
في هذه العملية.
أيضا ، لا علاقة لها قليلا:الخاص بك trap - EXIT
هو في سوبشيل (صراحة) ، لذلك لن يكون لها تأثير بعد عودة وظيفة التنظيف
من الواضح جدا من التجربة أن rsync
يتصرف مثل الأدوات الأخرى مثل ping
ولا ترث إشارات من الوالد باش الدعوة.
لذلك عليك أن تكون مبدعا قليلا في هذا وأن تفعل شيئا مثل ما يلي:
$ cat rsync.bash
#!/bin/sh
set -m
trap '' SIGINT SIGTERM EXIT
rsync -avz LargeTestFile.500M root@host.mydom.com:/tmp/. &
wait
echo FIN
الآن عندما أقوم بتشغيله:
$ ./rsync.bash
X11 forwarding request failed
building file list ... done
LargeTestFile.500M
^C^C^C^C^C^C^C^C^C^C
sent 509984 bytes received 42 bytes 92732.00 bytes/sec
total size is 524288000 speedup is 1027.96
FIN
ويمكننا أن نرى الملف لم نقل بالكامل:
$ ll -h | grep Large
-rw-------. 1 501 games 500M Jul 9 21:44 LargeTestFile.500M
كيف يعمل
الحيلة هنا هي أننا نقول باش عبر set -m
لتعطيل عناصر التحكم في الوظيفة على أي وظائف خلفية داخلها.نحن ثم الخلفية rsync
ثم تشغيل wait
الأمر الذي سينتظر على أمر التشغيل الأخير, rsync
, ، حتى يكتمل.
نحن ثم حراسة السيناريو بأكمله مع trap '' SIGINT SIGTERM EXIT
.