آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

پرسش و پاسخ شماره ۴۷

پرسش و پاسخ شماره ۴۷

چطور می‌توانم stderr را به یک لوله تغییر مسیر بدهم؟

یک لوله فقط می‌تواند خروجی استاندارد‎ (stdout)‎ برنامه را حمل کند. برای عبور دادن خروجی استاندارد خطا ‎ (stderr)‎ از میان لوله، لازم است stderr را به همان مقصد stdout تغییر مسیر بدهید. به طور اختیاری برای دریافت stderr تنها، می‌توانید stdout را ببندید یا به ‎ /dev/null‎ تغییر مسیر بدهید. چند نمونه کُد:

# Bourne
# می‌نویسد stdout و هم در stderr برنامه‌ایست که هم در 'myprog' فرض کنید  ‎

# را به لوله تغییر مسیر می‌دهد درحالیکه stderr نگارش اول ‎
# خروجی استاندارد نیز  باقی می‌ماند. (هردو مخلوط می‌شوند)‏‎
myprog 2>&1 | grep ...

#  به لوله تغییر مسیر داده می‌شود، بدون  stderr نگارش دوم ‎
#  .تغییرمسیر داده می‌شود ‎/dev/null‎ که به stdout حفظ کردن‎
myprog 2>&1 >/dev/null | grep ...

#       .در یک فایل stdout همان ایده، این دفعه با ذخیره 
myprog 2>&1 >file | grep ...

یک مثال ساده دیگر از تغییر مسیر stdout و stderr:

# Bourne
{ command | stdout_reader; } 2>&1 | stderr_reader

برای توضیحات بیشتر در مورد چگونگی عملکرد متقابل تغییر مسیرها و لوله‌ها پرسش و پاسخ شماره 55 را ببینید.

این مورد کاربرد واضحی با برنامه‌هایی از قبیل dialog دارد، که(با استفاده از ncurses) پنجره‌ها را در نمایشگر(خروجی استاندارد) رسم می‌کند و نتایج را به stderr بر می‌گرداند. یک روش کار با این برنامه می‌تواند تغییر مسیر stderr به یک فایل موقتی باشد. اما این ضروری نیست -- پرسش و پاسخ شماره 40 را برای مثالهای استفاده از dialog ببینید!

در مثال فوق(همچنین پرسش و پاسخ شماره 40)، ما به طور کلی stdout را رها کردیم، یا آن را به دستگاه شناخته شده‌ای فرستادیم(‎/dev/tty‎ برای ترمینال کاربر). همچنین ممکن است کسی فقط stderr را لوله‌کشی نماید اما تعامل با stdout را حفظ نماید(بدون شناخت مستدل از جایی که خروجی اسکریپت می‌رود). این اندکی ماهرانه است.

# Bourne
#                بدون تغییر stdout به لوله و نگاه داشتنstderr تغییر مسیر‎

exec 3>&1                       #       ذخیره مقدار فعلی خروجی استاندارد‎
myprog 2>&1 >&3 | grep ...      #  3 شماره  FD  ارسال خروجی استاندارد به‎
exec 3>&-                       #    .حالا بستن آن برای باقیمانده اسکریپت‎

#     http://www.tldp.org/LDP/abs/html/io-redirection.html    با تشکر از 

همان کار می‌تواند بدون exec انجام بشود:

# POSIX
$ myfunc () { echo "I'm stdout"; echo "I'm stderr" >&2; }
$ { myfunc 2>&1 1>&3 3>&- | cat  > stderr.file 3>&-; } 3>&1
I'm stdout
$ cat stderr.file
I'm stderr

توصیف‌گر شماره 3 بسته می‌شود‎ (3>&-)‎ بنابراین فرمانها از آن ارث نمی‌برند. توجه کنید bash دونسخه‌ای نمودن و بستن در یک تغییر مسیر را اجازه می‌دهد: ‎ 1>&3- ‎
 می‌توانید در لینوکس با آزمایش زیر تفاوتها را کنترل کنید:

# Bash
{ bash <<< 'lsof -a -p $$ -d1,2,3'   ;} 3>&1
{ bash <<< 'lsof -a -p $$ -d1,2,3' 3>&-  ;} 3>&1

نمایش dialog یک سطری:

# Bourne
exec 3>&1
dialog --menu Title 0 0 0 FirstItem FirstDescription 2>&1 >&3 | sed 's/First/Only/'
exec 3>&-

این یک پنجره dialog خواهد داشت که به طور صحیح کار می‌کند، بازهم خروجی استاندارد dialog خواهد بود(بازگردانده به stderr) که توسط sed جایگزین می‌شود.

یک نتیجه مشابه می‌تواند با جایگزینی پردازش حاصل شود:

# Bash
perl -e 'print "stdout\n"; warn "stderr\n"' 2> >(tr '[:lower:]' '[:upper:]')

این مثال خطای استاندارد را به میان فرمان tr لوله‌کشی می‌کند.

این آموزش تغییر مسیر را ببینید(با یک مثال که stdout را به یک لوله تغییر مسیر می‌دهد و stderr را به لوله دیگری).


CategoryShell

پرسش و پاسخ 47 (آخرین ویرایش ‎ 2012-03-05 11:30:04 ‎ توسط pgas)