خواندن سطر به سطر فایل، اگر یک دستور در داخل حلقه نیز stdin را بخواند، میتواند فایل ورودی را تهی کند، برای مثال:
# مثالی که کار نمیکند while IFS= read -r file; do ffmpeg -i "$file" -vcodec libxvid -acodec libfaac -ar 32000 "${file%.avi}".mkv done < <(find . -name '*.avi')
# مثالی که کار نمیکند while read host; do ssh "$host" some command done <hostslist
در اینجا چه اتفاقی رخ میدهد؟ اجازه بدهید مثال اول راببینیم. read سطری از ورودی استاندارد(FD 0) میخواند،آن را در پارامتر file قرار میدهد، و بعد ffmpeg اجرا میشود. مانند هر برنامه دیگری که شما از BASH اجرا میکنید، ffmpeg نیز ورودی استاندارد را به ارث میبرد، که بنا به دلایلی از آن میخواند. من نمیدانم چرا. اما در هر وضعیتی، موقعی که ffmpeg از stdin میخواند، تمام ورودی را از فرمان find جذب میکند، حلقه از گرسنگی میمیرد.
این هم چگونه کارآمد ساختن آن:
while IFS= read -r file; do ffmpeg -i "$file" -vcodec libxvid -acodec libfaac -ar 32000 "${file%.avi}".mkv </dev/null done < <(find . -name '*.avi')
به تغییر مسیر در سطر ffmpeg توجه نمایید: </dev/null. مثال ssh میتواند به همین ترتیب ، یا با گزینه -n اصلاح بشود (حداقل با OpenSSH).
گاهی اوقات شاید کار کردن با آنچه از ورودی استاندارد خوانده میشود، با حلقههای بزرگ دشوار گردد، یا ممکن است برنامه موقعی که شما </dev/null را به آن اضافه میکنید رفتارش را تغییر بدهد. در این وضعیت شما میتوانید کاری کنید که فرمان read از توصیفگر فایل متفاوتی استفاده کند، که کمتر محتمل است یک برنامه تصادفی از آن بخواند:
while read <&3 line; do ...... done 3<file
یا از گزینه -u فرمان read استفاده کنید(POSIX نیست):
# Bash while read -u 3 line; do ...... done 3<file
پرسش و پاسخ 89 (آخرین ویرایش 2013-05-17 20:58:31 توسط GreyCat)