یک فرمان exec <filename ورودی استاندارد را به فایل تغییر مسیر میدهد. از آن نقطهای که قرار دارد تمام stdin به جای منبع معمولیاش (معمولاً ورودی صفحه کلید است)، از آن فایل میآید. این روشی برای خواندن سطر به سطر یک فایل و احتمالاً تجزیه هر سطر ورودی با sed و/یا awk فراهم میسازد.
مثال 20-1. تغییر مسیر دادن stdin با استفاده از exec
#!/bin/bash #تغییر مسیر stdin با کاربرد exec. exec 6<&0 #پیوند زدن توصیفگر فایل شماره 6 با stdin. #stdin را ذخیره میکند. exec < data-file #stdin به وسیله فایل data-file تعویض شده read a1 #سطر نخست از فایل data-file را میخواند. read a2 #سطر دوم از فایل data-file را میخواهد. echo echo "Following lines read from file." echo "-------------------------------" echo $a1 echo $a2 echo; echo; echo exec 0<&6 6<&- #اکنون بازیابی stdin از fd #6، جایی که ذخیره شده بود، و بستن fd #+شماره 6 ( 6<&- ) برای آزاد کردن آن جهت استفاده سایر پردازشها. # #<&6 6<&- نیز کار میکند. echo -n "Enter data " read b1 #اکنون عملیات خواندن به روش مورد انتظار، خواندن از stdin عادی. echo "Input read from stdin." echo "----------------------" echo "b1 = $b1" echo exit 0
به طور مشابهی، یک فرمان exec >filename خروجی استاندارد را به یک فایل هدف تغییر مسیر میدهد. این تمام خروجی فرمان را که به طور عادی به stdout میرفت، به آن فایل میفرستد.
exec N > filename بر تمام اسکریپت یا پوسته جاری اثر میکند. اما، تغییر مسیر در PID اسکریپت یا پوسته از آن نقطهای روی آن تغییر کرده است. N > filename فقط بر پردازشهای به تازگی منشعب میشوند اثر میکند، نه بر تمام اسکریپ یا پوسته. با تشکر از احمد درویش برای اشاره کردن به این مورد. |
مثال 20-2. تغییر مسیر دادن stdout با استفاده از exec
#!/bin/bash # LOGFILE=logfile.txt exec 6>&1 #ارتباط دادن توصیفگر فایل شماره 6 با stdout. #stdout را ذخیره میکند. exec > $LOGFILE #stdout با فایل logfile.txt تعویض گردیده. # #تمام خروجی فرمانها در این بلوک به فایل $LOGFILE فرستاده میشوند. echo -n "Logfile: " date echo "-------------------------------------" echo echo "Output of \"ls -al\" command" echo ls -al echo; echo echo "Output of \"df\" command" echo df # exec 1>&6 6>&- #بازیابی stdout و بستن توصیفگر فایل شماره 6 echo echo "== stdout now restored to default == " echo ls -al echo exit 0
مثال 20-3. تغییر مسیر دادن هردو stdin و stdout با exec در یک اسکریپت
#!/bin/bash #upperconv.sh #یک فایل ورودی مشخص شده را به حروف بزرگ تبدیل میکند. E_FILE_ACCESS=70 E_WRONG_ARGS=71 if [ ! -r "$1" ] #آیا فایل ورودی تعیین شده قابل خواندن است؟ then echo "Can't read from input file!" echo "Usage: $0 input-file output-file" exit $E_FILE_ACCESS fi #حتی اگر فایل ورودی ($1) مشخص نشده باشد، #+همان یک خطا خارج خواهد شد (چرا؟). if [ -z "$2" ] then echo "Need to specify output file." echo "Usage: $0 input-file output-file" exit $E_WRONG_ARGS fi exec 4<&0 exec < $1 #از فایل ورودی خواهد خواند. exec 7>&1 exec > $2 #در فایل خروجی خواهد نوشت. #با فرض قابل نوشتن بودن فایل خروجی (بررسی را اضافه کنید). #-------------------------------------------------------- cat - | tr a-z A-Z #تبدیل به حروف بزرگ. # #از stdin میخواند. # #در stdout مینویسد. #به هرحال، هم stdin و هم stdout تغییر مسیر داده شدهاند. #توجه نمایید که cat میتواند صرفنظر بشود. #-------------------------------------------------------- exec 1>&7 7>&- #بازیابی stout. exec 0<&4 4<&- #بازیابی stdin. #بعد از بازگرداندن، سطر زیر به طوریکه مورد انتظار است در stdout چاپ میشود. echo "File \"$1\" written to \"$2\" as uppercase conversion." exit 0
تغییر مسیر ورودی-خروجی یک روش چابک پرهیز نمودن از مشکل رنجشآور غیر قابل دسترس بودن متغیرها دون یک پوسته فرعی است.
مثال 20-4. پرهیز از پوسته فرعی
#!/bin/bash #avoid-subshell.sh #پیشنهاد شده توسط Matthew Walker Lines=0 echo cat myfile.txt | while read line; do { echo $line (( Lines++ )); #مقادیر افزایش یافته این متغیر #+در خارج حلقه قابل دسترس نیست. #مشکل پوسته فرعی. } done echo "Number of lines read = $Lines" #0 #Wrong! echo "------------------------" exec 3<> myfile.txt while read line <&3 do { echo "$line" (( Lines++ )); #مقادیر افزایش یافته این متغیر #+خارج از حلقه قابل دستیابی است. #بدون پوسته فرعی، بدون مشکل. } done exec 3>&- echo "Number of lines read = $Lines" #8 echo exit 0 #سطرهای زیر توسط اسکریپت دیده نمیشوند. $ cat myfile.txt Line 1. Line 2. Line 3. Line 4. Line 5. Line 6. Line 7. Line 8.