جایگزینی پردازش یک توسعه بسیار سودمند BASH است. مشابه "command" | getline در awk میباشد و بخصوص برای کنار گذاشتن پوستههای فرعی معلول خطلولهها اهمیت دارد.
جایگزینی پردازش در دو شکل ظاهر میشود: <(some command) و >(some command). هر کدام نسبت به سیستم عامل، باعث میشوند یا یک FIFO در /tmp یا /var/tmp ایجاد بشود، یا یک دستگاه ویژه توصیفگر فایل (/dev/fd/*)، استفاده بشود. ترکیب دستوری جایگزینی توسط نام FIFO یا FD تعویض میگردد، وفرمان داخل آن در پسزمینه اجرا میگردد. جایگزینی در همان مرحله بسط پارامتر و جایگزینی فرمان انجام میشود.
یکی از رایجترین موارد استفاده این ویژگی برای پرهیز از ایجاد فایلهای موقتی است، به عنوان مثال، موقع کاربرد diff(1):
ادامه مطلبBashهیچ روش درونی برای استفاده از قالب ها( templates) ندارد. اگر چه، نسبت به اهداف واقعی خود، ممکن است فقط بتوانید شگرد ارزیابی فایل با یک bash جدید یا پوسته نمونه را به کار ببرید.
به هر حال، این مطلب در صفحه TemplateFiles بحث شده است.
پرسش و پاسخ 110 (آخرین ویرایش 2013-03-18 18:07:40 توسط 12)
به طور معمول موقعی که اشخاص این پرسش را مطرح میکنند، به دلیل آنست که میخواهند خطاهای کاربر را تشخیص داده و پیغام مناسبی برای آن تهیه کنند. یک نظریهای هست که میگوید نباید کاربر یونیکس را به این طریق نازپرورده نمود، و اگر کاربری حقیقتاً بخواهد در عوض منبع کردن اسکریپت شما، آن را اجرا کند،شما نباید برای این کار او را نکوهش کنید. حال از این که بگذریم، ما میتوانیم پرسش را به نحو دیگری که در واقع باید پرسیده شود، بیان کنیم:
من میخواهم اگر کاربر به جای منبع کردن اسکریپت آنرا از پوسته محاورهای اجرا نماید، یک پیغام خطا نمایش داده و از اجرای اسکریپت صرف نظر گردد.
کلید در اینجا، و دلیل آنکه من پرسش را به این طریق جملهبندی مجدد نمودهام، آنست که شما عملاً نمیتوانید آنچه را کاربر تایپ نموده است تعیین کنید، اما میتوانید تعیین کنید آیا کُد در حال تفسیر شدن با یک پوسته محاورهای است. این کار را باکنترل یک i در محتوای متغیر $- انجام بدهید:
# POSIX(?) case $- in *i*) : ;; *) echo "You should dot me in" >&2; exit 1;; esac
یا با استفاده از ترکیب دستوری غیر-POSIX:
# Bash/Ksh if [[ $- != *i* ]]; then echo "You should dot me in" >&2; exit 1 fi
البته، این مورد در حالتهای ترفندآمیزی مانند «من میخواهم فایل من از یک اسکریپت غیرمحاورهای نقطهای بشود...» کار نمیکند. برای آن حالتها، پاراگراف اول این صفحه را ببینید.
پرسش و پاسخ 109 (آخرین ویرایش 2012-09-11 07:43:44 توسط dslb-088-072-055-065)
برای انجام این کار روشهای بیشماری موجود است، اما تمام آنها محدود به ابزارهای در دسترس هستند. من به چاره سازیهای زیر رسیدم .
اگر میخواهید در انتظار تمام پردازشهای فرزند بمانید، به سادگی wait را بدون شناسه احضار کنید.
اگر فقط میخواهید منتظر برخی، اما نه تمام آنها، بمانید و نگران وضعیت خروج آنها نمیباشید، میتوانید wait را با PIDهای چندگانه فراخوانی کنید:
wait $pid1 $pid2
اگر نیاز دارید، بدانید آیا فرزند موفق یا ناموفق بوده، آنوقت شاید:
waitall() { # PID... ## .انتظار برای خروج فرزند و نمایش آنکه آیا همه با وضعیت صفر خارج شدهاند local errors=0 while :; do debug "Processes remaining: $*" for pid in "$@"; do shift if kill -0 "$pid" 2>/dev/null; then debug "$pid is still alive." set -- "$@" "$pid" elif wait "$pid"; then debug "$pid exited with zero exit status." else debug "$pid exited with non-zero exit status." ((++errors)) fi done (("$#" > 0)) || break # متوقف گردد؟ sleep وقتی فرزند خاتمه داده میشود، چطور این :برای انجام sleep ${WAITALL_DELAY:-1} done ((errors == 0)) } debug() { echo "DEBUG: $*" >&2; } pids="" for t in 3 5 4; do sleep "$t" & pids="$pids $!" done waitall $pids
حلقهزنی بواسطه kill -0 میتواند بسیار بیکفایت باشد.
اطلاعات مفیدتر میتواند در صفحه مدیریت پردازش یافت شود.
پرسش و پاسخ 108 (آخرین ویرایش 2011-09-12 23:03:28 توسط GreyCat)
روشهای بیشماری برای انجام این کار هست، اما تمام آنها یا به ابزارهای در دسترس محدود میشوند، یا کُند هستند. ما چند نمونه را نشان خواهیم داد.
بیایید اول با روش آهسته قابل حمل شروع کنیم و با این نمونه آن را انجام بدهیم:
# POSIX while IFS= read -r line; do echo "$(date +%Y%m%d-%H:%M:%S) $line" done
و یکی دیگر که حتی کُندتر است:
awk '{system("printf \"`date +%T ` \">&2")}$0'
و سومی، که به طور جزئی سریعتر است، اما ممکن است بعضی از سطرهای ورودی را خُرد کند:
xargs -I@ -n1 date "+%T @"
اشکال واضح تمام مثالهای فوق آنست که ما در حال اجرای فرمان خارجی date برای هر سطر از ورودی میباشیم. اگر ما در هر دو ثانیه فقط یک سطر دریافت کنیم، شاید این پذیرفتنی باشد. اما اگر ما در حال تلاش برای مُهر تاریخ زدن به جریانی باشیم که در هر ثانیه سطرهای بسیاری تحصیل میکند، حتی ممکن است قادر به همگام شدن با نویسنده نباشیم.
روشهای متنوعی برای انجام این کار، بدون تولید پردازش فرزند(forking) به ازای هر سطر، وجود دارد، اما تمام آنها نیازمند ابزارهای غیر استاندارد یا پوستههای خاص، میباشند. Bash 4.2 میتواند آن را با printf انجام بدهد:
# Bash 4.2 while read -r; do printf "%(%Y%m%d-%H:%M:%S)T %s\n" -1 "$REPLY" done
مشخص کننده قالب %(...)T در bash نگارش 4.2 جدید است. شناسه -1 به او میگوید از زمان جاری به جای زمان عبور داده شده به عنوان شناسه، استفاده کند. برای جزئیات، صفحه man مربوط را ملاحظه نمایید.
یک روش دیگر، نوشتن یک perl یک سطری است:
perl -p -e '@l=localtime; printf "%04d%02d%02d-%02d:%02d:%02d ", 1900+$l[5], $l[4], $l[3], $l[2], $l[1], $l[0]'
مطمئن هستم شخصی با یک جایگزین 7 بایتی پیش خواهد آمد که همان کار را با استفاده از ترکیب دستوری جادویی پرل، که من هرگز قبلاً ندیدهام و نمیتوانم بفهمم، انجام میدهد، ....
ابزارهای دیگری مخصوصاً برای نشانهگذاری زمان فایلهای ثبت وقایع و مشابه، وجود دارد. یکی از آنها multilog از daemontools میباشد، اما قالب نشانهگذاری زمان آن TAI64N است که قابل خواندن انسانی نیست. دیگری ts از بسته moreutils میباشد.
پرسش و پاسخ 107 (آخرین ویرایش 2012-05-19 12:23:00 توسط GreyCat)