لولهکشی stdout یک فرمان به stdin فرمانی دیگر، یک شگرد قدرتمند است. اما، اگر به لولهکشی stdout چند فرمان، نیاز داشته باشید چطور؟ اینجاست که جایگزینی پردازش به کار میآید.
جایگزینی پردازش، خروجی یک پردازش (یا پردازشها) را به stdin یک پردازش دیگر تغذیه میکند.
>(command_list)
<(command_list)
جایگزینی پردازش، فایلهای /dev/fd/<n> را برای فرستادن نتایج پردازش(های) داخل پرانتزها به یک پردازش دیگر به کار میبرد. [1]
هیچ فاصلهای میان < یا > و پرانتزها وجود ندارد. وجود فاصله یک پیغام خطا خواهد داد. |
bash$ echo >(true) /dev/fd/63 bash$ echo <(true) /dev/fd/63 bash$ echo >(true) <(true) /dev/fd/63 /dev/fd/62 bash$ wc <(cat /usr/share/dict/linux.words) 483523 483523 4992010 /dev/fd/63 bash$ grep script /usr/share/dict/linux.words | wc 262 262 3601 bash$ wc <(grep script /usr/share/dict/linux.words) 262 262 3601 /dev/fd/63
Bash یک لوله با دو توصیفگر فایل --fIn و fOut--، ایجاد میکند. stdin فرمان true را به fOut متصل میکند(dup2(fOut, 0))، سپس Bash یک شناسه /dev/fd/fIn به فرمان echo عبور میدهد. در سیستمهای فاقد فایلهای /dev/fd/<n>، ممکن است Bash از فایلهای موقت استفاده نماید. (سپاس، S.C.) |
جایگزینی پردازش میتواند خروجی دو فرمان متفاوت، یا حتی خروجی گزینههای مختلف یک فرمان را مقایسه نماید.
bash$ comm <(ls -l) <(ls -al) total 12 -rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0 -rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2 -rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh total 20 drwxrwxrwx 2 bozo bozo 4096 Mar 10 18:10 . drwx------ 72 bozo bozo 4096 Mar 10 17:58 .. -rw-rw-r-- 1 bozo bozo 78 Mar 10 12:58 File0 -rw-rw-r-- 1 bozo bozo 42 Mar 10 12:58 File2 -rw-rw-r-- 1 bozo bozo 103 Mar 10 12:58 t2.sh
جایگزینی فرمان میتواند محتویات دو دایرکتوری را -- برای دیدن آن که کدام نامفایل در یکی هست اما در دیگری نیست -- مقایسه کند.
diff <(ls $first_directory) <(ls $second_directory)
برخی کاربردها و استفادههای جایگزینی پردازش:
read -a list < <( od -Ad -w24 -t u2 /dev/urandom ) #خواندن لیست اعداد تصادفی از /dev/urandom، پردازش آنها با od #+و تغذیه به ورودی استاندارد read . . . #از اسکریپت مثال insertion-sort.bash اهدایی JuanJo Ciarlante.
PORT=6881 #bittorrent #پویش درگاه برای کسب اطمینان از آن که شرارتی در کار نباشد. netcat -l $PORT | tee>(md5sum ->mydata-orig.md5) | gzip | tee>(md5sum - | sed 's/-$/mydata.lz2/'>mydata-gz.md5)>mydata.gz # gzip -d<mydata.gz | md5sum -c mydata-orig.md5) #MD5sum نسخه اصلی stdin را وارسی میکند و مسائل فشردگی را تشخیص میدهد. #این مثال به وسیله Bill Davidsen اهدا گردیده است. #(با ویرایش اندک به وسیله نگارنده راهنمای ABS).
cat <(ls -l) #مشابه با ls -l | cat sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin) #تمام فایلها در سه دایرکتوری اصلی bin را لیست و بر حسب نامفایل مرتب مینماید. #توجه کنید که سه دستور متفاوت به sort تغذیه میشوند. diff <(command1) <(command2) #اختلاف خروجی فرمان را ارایه میکند. tar cf >(bzip2 -c > file.tar.bz2) $directory_name #tar cf /dev/fd/?? $directory_name و bzip2 -c > file.tar.bz2 را احضار میکند. # #به علت ویژگی سیستمِ /dev/fd/<n>، لازم نیست لوله بین دو فرمان با نام باشد. # #میتواند به صورت زیر شبیهسازی بشود. # bzip2 -c < pipe > file.tar.bz2& tar cf pipe $directory_name rm pipe #یا exec 3>&1 tar cf /dev/fd/4 $directory_name 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&- exec 3>&- #با تشکر از Stéphane Chazelas
این هم یک شیوه خنثی کردن مشکل یک echo لولهکشی شده به حلقه while-read در حال اجرا در یک پوسته فرعی.
مثال 23-1. تغییر مسیر بلوک کد بدون انشعاب زدن
#!/bin/bash #حلقه while-read با جایگزینی پردازش. #این مثال به وسیله Tomas Pospisek اهدا گردیده. #(توسط نگارنده راهنمای ABS کاملا ویرایش گردیده است.) echo echo "random input" | while read i do global=3D": Not available outside the loop." #...زیرا در یک پوسته فرعی اجرا میگردد. done echo "\$global (from outside the subprocess) = $global" #(از بیرونِ پردازش فرعی) $global = echo; echo "--"; echo while read i do echo $i global=3D": Available outside the loop." #... زیرا در یک پوسته فرعی اجرا نمیگردد. done < <( echo "random input" ) # echo "\$global (using process substitution) = $global" #ورودی تصادفی # echo; echo "##########"; echo #و به همچنین . . . declare -a inloop index=0 cat $0 | while read line do inloop[$index]="$line" ((index++)) #در یک پوسته فرعی اجرا میشود، بنابراین ... done echo "OUTPUT = " echo ${inloop[*]} #...چیزی منعکس نمیشود. echo; echo "--"; echo declare -a outloop index=0 while read line do outloop[$index]="$line" ((index++)) #در پوسته فرعی اجرا نمیشود، بنابراین ... done < <( cat $0 ) echo "OUTPUT = " echo ${outloop[*]} #...تمام اسکریپت منعکس میگردد. exit $?
مثال 23-2. تغییر مسیر دادن خروجی جایگزینی پردازش به درون یک حلقه.
#!/bin/bash # #به وسیله Diego Molina ایجاد گردیده است (تشکر!). declare -a array0 while read do array0[${#array0[@]}]="$REPLY" done < <( sed -e 's/bash/CRASH-BANG!/' $0 | grep bin | awk '{print $1}' ) #متغیر پیشفرض read یعنی $REPLY را توسط جایگزینی پردازش #+تنظیم میکند، سپس به داخل یک آرایه کپی مینماید. echo "${array0[@]}" exit $?bash$ bash psub.bash #!/bin/CRASH-BANG! done
خوانندهای این مثال جالب جایگزینی فرمان را فرستاده است.
#قطعه اسکریپت اخذ شده از توزیع SuSE # while read des what mask iface; do #چند فرمان ... done < <(route -n) #اولین < تغییر مسیر است، دومی جایگزینی پردازش است. #برای تست این، بیاید آن را برای انجام کاری آماده کنیم. while read des what mask iface; do echo $des $what $mask $iface done < <(route -n) #خروجی: #Kernel IP routing table #Destination Gateway Genmask Flags Metric Ref Use Iface # # #به طوریکه Stéphane Chazelas اشاره میکند، #+یک معادل آسانفهمتر آن عبارت است از: route -n | while read des what mask iface; do #متغیرها طبق خروجی لوله تنظیم میشوند. echo $des $what $mask $iface done #این کد همان خروجی بالا را تحویل میدهد. #به هر حال، چنانکه Ulrich Gayer شرح میدهد، این معادل ساده #+شده، بواسطه حلقه while از یک پوسته فرعی استفاده میکند، و #+بنابراین وقتی لوله خاتمه مییابد، متغیرها ناپدید میگردند. # #اگر چه، Filip Moritz توضیح میدهد که تفاوت ظریفی بین دو #+مثال فوق وجود دارد، همچنانکه در ادامه نمایش داده میشود. ( route -n | while read x; do ((y++)); done echo $y #$y هنوز تنظیم نشده است while read x; do ((y++)); done < <(route -n) echo $y #$y دارای تعداد سطرهای خروجی route -n است ) More generally spoken ( : | x=x #به نظر میرسد یک پوسته فرعی راهاندازی میشود، مانند : | ( x=x ) #درحالیکه، در x=x < <(:) #پوسته فرعی راهاندازی نمیشود. ) #این موقع تجزیه csv و مشابه آن، سودمند است. #آنچه که قطعه کد اصلی SuSE به طور موثر انجام میدهد.
[1] | این دارای نتیجه همانند یک لوله بانام (فایل موقت) است، و در حقیقت در آغاز لولههای با نام در جایگزینی پردازش به کار رفتند. |