یک لوله فقط میتواند خروجی استاندارد (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 را به لوله دیگری).
پرسش و پاسخ 47 (آخرین ویرایش 2012-03-05 11:30:04 توسط pgas)