"glob"زیرنویس1 نام رایج برای یک مجموعه از ویژگیهای Bash است که انواع معینی از الگوها را انطباق یا بسط میدهد. برخی مترادفها برای globbing (نسبت به مضمونی که در آن ظاهر میشود) انطباق الگو، بسط الگو، بسط نام فایل، و مانند آن میباشند. یک glob ممکن است مانند *.txt به نظر آید و موقعی که برای انطباق نام فایلها به کار میرود، گاهی اوقات یک کاراکتر عام نامیده میشود.
globهای سنتی پوسته ترکیب دستوری بسیار سادهای را به کار میبرند، که نسبت به عبارت منظم کمتر گویا میباشند. در یک glob با اکثر کاراکترها به طور لفظی رفتار میشود، اما یک کاراکتر * با هیچ یا چند کاراکتر مطابقت میکند یک کاراکتر ? صریحاً با یک کاراکتر مطابقت میکند، و [...] بر هر کاراکتر منفرد در یک مجموعه مشخص شده منطبق میگردد ( محدودهها در پایین را ببینید). به طور ضمنی شروع و انتهای تمام globها مهار میگردد. برای مثال:
* |
بر هر رشتهای با هر طولی منطبق میگردد |
foo* |
با هر رشتهای که با foo شروع میشود، مطابقت میکند |
*x* |
با هر رشته شامل یک x مطابقت میکند( ابتدا، وسط، یا انتها) |
*.tar.gz |
بر هر رشتهای که به .tar.gz ختم گردد، منطبق میشود |
*.[ch] |
با هر رشتهای که با .c یا .h خاتمه مییابد، تطبیق میکند |
foo? |
با foot یا foo$ مطابقت دارد، اما با fools خیر |
Bash جانشینهایی را که به طور غیر نقلقولی در فرمانها ظاهر میگردند، توسط تطبیق با نام فایلهای دایرکتوری جاری بسط میدهد. بسط glob به یک یا چند کلمه منجر میگردد (اگر برخی گزینهها تنظیم باشند به 0 کلمه یا بیشتر)، و آن کلمات (نام فایلها) در فرمان استفاده میشوند. برای مثال:
tar xvf *.tar # .بسط مییابد tar xvf file1.tar file2.tar file42.tar ... به # (که معمولاً چیزی نیست که کسی بخواهد)
حتی اگر نام فایلی شامل فضاهای سفید داخلی باشد، بسط یک جانشین که با آن نام فایل منطبق گردد باز هم هر نام فایل را به عنوان یک کلمه منفرد حفظ میکند. برای مثال:
# :این مورد حتی اگر نام فایل شامل فضای سفید باشد، مطمئن است for f in *.tar; do tar tvf "$f" done # :اما این یکی مطمئن نیست for f in $(ls | grep '\.tar$'); do tar tvf "$f" done
در دومین مثال فوق، خروجی ls فیلتر میشود، و سپس نتیجه کل خط لوله برای به کار رفتن به عنوان کمیتهای تکراری حلقه، به کلمات تقسیم میشود. تفکیک کلمه روی فضاهای سفید داخل هر نام فایل روی میدهد، که در حالت کلی آن را بیفایده میکند. مثال نخست چنین مشکلی ندارد، زیرا نام فایلهای فراهم شده توسط glob تحت تأثیر تفکیک کلمه مجدد قرار نمیگیرند. برای مثالهای بیشتری از این قبیل، دامهای Bash را ببینید.
همچنین جانشینها در Bash در چند محل برای انطباق الگو به کار میروند. مرسومترین آن در فرمان case میباشد:
case "$input" in [Yy]|'') confirm=1;; [Nn]*) confirm=0;; *) echo "I don't understand. Please try again.";; esac
الگوها (که توسط کاراکترهای | جدا میشوند) در برابر اولین کلمه پس از خود case مطابقت داده میشوند. اولین الگویی که منطبق گردد، «پیروز میشود»، باعث اجرا شدن فرمانهای متناظر میگردد.
Bash همچنین اجازه میدهد جانشینها در طرف راست یک مقایسه درون یک فرمان [[ ظاهر بشوند:
if [[ $output = *[Ee]rror* ]]; then ...
سرانجام، globها در جریان بسط پارامتر برای نشان دادن الگوهایی که ممکن است در حین یک جایگزینی زدوده یا تعویض بشوند، به کار میروند. مثالهای ساده (در صفحه ارجاع شده قبلی تعداد بسیار بیشتری وجود دارد):
filename=${path##*/} # مطابقت نماید را حذف میکند(حریص است) */ الگویی که از ابتدا با dirname=${path%/*} # شود را حذف میکند (حریص نیست) /* الگویی که از انتهامنطبق بر printf '%s\n' "${arr[@]}" # نسخه برداری یک آرایه، هر عضو در یک سطر printf '%s\n' "${arr[@]/error*/}" # در صورت انطباق error* رونوشت آرایه، حذف
(مرجع: آرایهها، نقلقولها، و printf.)
جانشینها با استفاده از کروشهها میتوانند یک محدوده یا class کاراکترها را تعیین کنند. این مطلب توانایی تطابق در برابر یک مجموعه از کاراکترها را به شما ارائه میکند. برای مثال:
[abcd] |
با a یا b یا c یا dمطابقت میکند |
[a-d] |
در صورتی که منطقه شما C یا POSIX باشد، همانند مورد فوق است. در غیر اینصورت، Implementation-defined میباشد. |
[!aeiouAEIOU] |
با هر کاراکتری به غیر از a, e, i, o, u و حروف بزرگ همتای آنها مطابقت دارد |
[[:alnum:]] |
با هر کاراکتر الفبا عددی (حرف ویا عدد) در منطقه جاری مطابقت میکند |
[[:space:]] |
بر هر کاراکتر فضای سفید منطبق میشود |
[![:space:]] |
بر هر کاراکتری که فضای سفید نیست انطباق دارد |
[[:digit:]_.] |
با هر رقم، یا _ یا . مطابقت میکند |
Implementation-defined به معنای آن است که ممکن است در یک ماشین چنانکه انتظار دارید کار کند، اماروی یک ماشین دیگر نتایج کاملاً متفاوتی ارائه کند. از ترکیب m-n استفاده نکنید مگر آنکه اول به طور صریح منطقه خود را به C تنظیم کرده باشید، یا ممکن است نتایج غیره منتظره به دست آورید. در صورتیکه میسر باشد، عبارتهای کلاس کاراکتری POSIX باید ترجیح داده شوند.
علاوه بر globهای سنتی (پشتیبانی شده توسط تمام پوستههای هم خانواده Bourn) که تا اینجا دیدهایم، Bash(و پوسته Korn) globهای توسعه یافته را ارائه میکند که دارای قدرت حاکی از عبارتهای منظم میباشد. پوسته Korn به طور پیشفرض اینها را فعال میکند، در Bash، شما باید برای فعال کردن آنها فرمان زیر را در پوسته (یا در آغاز اسکریپت) اجرا کنید:
shopt -s extglob
مرجع انطباق الگو، ترکیب دستوری ارائه شده در اینجا را تشریح میکند:
الگوها در یک لیست، با کاراکترهای | جدا میشوند.زیرنویس 2
globهای توسعه یافته به شما اجازه میدهند تعدادی از مشکلات را حل کنید که در غیر اینصورت نیاز به مقدار نسبتاً فوقالعادهای کد ناخوشآیند دارد، برای مثال:
# مطابفت میکنند *.jpg برای حذف تمام فایلها غیر از آنهایی که با rm !(*.jpg) # *.jpg و *.gif و *.png حذف تمام فایلها غیر از rm !(*.jpg|*.gif|*.png)
# به استثنای یکی از آنها به آدرس مورد نظر MP3 برای کپی تمام فایلهای cp !(04*).mp3 /mnt
برای استفاده از یک extglob در بسط پارامتر (این مورد با read میتواند در یک جمله BASH نیز انجام بشود):
# برای زدودن فضاهای سفید از ابتدا و انتهای یک متغیر x=${x##+([[:space:]])}; x=${x%%+([[:space:]])}
الگوهای glob توسعه یافته، میتوانند تودرتو نیز باشند.
[[ $fruit = @(ba*(na)|a+(p)le) ]] && echo 'Nice fruit'
به دلیل اینکه گزینه extglob روش تجزیه شدن برخی کاراکترها را تغییر میدهد، داشتن یک سطرجدید (نه فقط یک سمی کالن ) میان فرمان shopt و هر فرمانی که متعاقب globهای توسعه یافته به کار میرود، لازم میباشد. بعلاوه، نمیتوانید shopt -s extglob را داخل یک بلوک دستور که globهای توسعه یافته را استفاده میکند، قرار بدهید، زیرا بلوک موقعی که متمایز میشود باید به عنوان یک کل تجزیه بشود، فرمان shopt تا وقتی بلوک ارزیابی میشود، یعنی جایی که دیگر خیلی دیر است، تأثیری نخواهد داشت. در حقیقت چون bash تمامیت بلوک دستور را قبل از هرگونه ارزیابی آن، تجزیه میکند، لازم است شما extglob را بیرون از خارجیترین بلوک قرار بدهید.
بنابراین، اگر از این گزینه در اسکریپت استفاده میکنید، بهتر است آن را درست زیر سطر شبانگ، یا هر چه نزدیکتر به آن در حالیکه بازهم میتوانید رسیدن به هدف را تأمین کنید، قرار بدهید.
#!/usr/bin/env bash
# Copyright (c) 2012 Foo Corporation
shopt -s extglob # nullglob dotglob و سایرین از قبیل
اگر کد شما یک اسکریپت نیست، اما در عوض source میشود، و خودش باید extglob را برقرار کند:
SourcedFile.sh if ! shopt extglob; then ClearExtGlob_SourcedFile_sh=1 shopt -s extglob fi # تا extglob مفهوم اصلی نهفته در پسِ گزینههای پایین آن است که تجزیه # زمان ارزیابی به تعویق افتد declare -a s='( !(x) )' echo "${a[@]}" echo "${InvalidVar:-!(x)}" eval 'echo !(x)' # using eval if no other option. if [ "${ClearExtGlob_SourcedFile_sh}" == "1" ]; then unset ClearExtGlob_SourcedFile_sh shopt -u extglob fi test.sh shopt -u extglob if true; then source ./SourcedFile.sh fi
اگر یک glob در تطابق با هر نام فایلی ناموفق باشد، به طور معمول پوسته آن را به تنهایی باقی میگذارد. این مطلب به معنای آن است که glob خام به فرمان عبور داده میشود، به این صورت:
$ ls *.ttx ls: cannot access *.ttx: No such file or directory
این مورد به فرمان اجازه میدهد که جانشینی که شما استفاده کردهاید را ببیند، و در یک پیغام خطا آن را به کار ببرد. اگر در Bash گزینه nullglob تنظیم شود، در هر حال، یک glob که با هیچ فایلی منطبق نمیگردد کاملاً حذف میشود.این مطلب در اسکریپتها مفید است، اما در خط فرمان تا اندازهای گیجکننده میباشد، چون انتظارات بسیاری از ابزارهای استاندارد را نقض میکند (برای یک جایگزین بهتر failglob را در ادامه ببینید):
# در اسکریپتها مناسب است shopt -s nullglob oggs=(*.ogg) for ogg in "${oggs[@]}"; do ... # !در خط فرمان نامناسب shopt -s nullglob ls *.ttx # را بدون شناسه اجرا میکند و تمام موارد را لیست میکند "ls" فرمان
اگر یک الگو در انطباق ناموفق شود، bash یک خطای بسط گزارش میکند. این مورد در خط فرمان میتواند مفید باشد:
# !مناسب در خط فرمان $ touch *.foo # را ایجاد میکند '*.foo' اگر در انطباق جانشین ناموفق شود فایل $ shopt -s failglob $ touch *.foo # اجرا نمیشود touch با تنظیم گزینه فوق فرمان -bash: no match: *.foo
طبق قرارداد، فایلی که نام آن با یک نقطه (dot) شروع میشود فایل پنهان است و توسط ls نشان داده نمیشود. globbing همان قرارداد را به کار میبرد -- نام فایلهای شروع شده با نقطه به وسیله یک glob منطبق نمیشوند، مگر اینکه glob نیز با یک نقطه شروع بشود. Bash دارای یک گزینه dotglob میباشد که انطباق «فایلهای نقطهای» را اجازه میدهد:
shopt -s dotglob nullglob files=(*) echo "There are ${#files[@]} files here, including dot files and subdirs"
لازم است توجه شود که وقتی dotglob فعال میشود، * با فایلهایی مانند .bashrc منطبق میگردد، اما با دایرکتوریهای . یا .. خیر. این کاملاً مستقل از مشکل انطباق «فقط فایلهای نقطهای» است -- یک glob به صورت .* با موارد . و .. نیز منطبق خواهد شد، معمولاً باعث مشکلاتی میگردد. بخش بعد را ببینید.
متغیر GLOBIGNORE متعلق به Bash (نه shopt) به شما اجازه میدهد الگوهایی را که یک glob نباید تطبیق ب دهد، تعیین نمایید. این گزینه به شما اجازه میدهد مشکل مفتضح «من میخواهم تمام فایلهای نقطهای منطبق شوند اما
$ echo .* . .. .bash_history .bash_logout .bashrc .inputrc .vimrc $ GLOBIGNORE=.:.. $ echo .* .bash_history .bash_logout .bashrc .inputrc .vimrc
glob (آخرین ویرایش 2012-07-21 11:21:48 توسط 77)
$ mkdir mytest $ cd mytest $ touch {,a,b}{2,a2,12,c,aaa,bbbb} $ ls12 2 a12 a2 aa2 aaa aaaa abbbb ac b12 b2 ba2 baaa bbbb bbbbb bc c # ایجاد گردیدهاند touch فایلهایی که با فرمان $ echo ?(a|b)22 a2 b2 $ echo *(a|b)22 a2 aa2 b2 ba2 $ echo +(a|b)2a2 aa2 b2 ba2 $ echo @(a|b)2a2 b2 $ echo !(a|b)212 2 a12 aa2 b12 ba2
در اینجا لیست الگوها (a
در مورد بعدی یعنی *(a
و یک مثال دیگر با تعداد فایلهای بیشتر:
$ pwd # دقت کنید که در همان دایرکتوری باشید~/mytest $ rm ./* $ touch {,a,b}{2,a2,12,c,aaa,bbbb,222,ab23333} $ ls # لیست فایلهای ایجاد شده با دستور فوق را مشاهده میکنید12 222 a2 aa2 aaaa ab23333 ac b2 ba2 bab23333 bbbbb c 2 a12 a222 aaa aab23333 abbbb b12 b222 baaa bbbb bc $ echo ?(a|b)2* # در این مثال کاراکتر عام * را نیز به کار بردهایم2 222 a2 a222 b2 b222 $ echo *(a|b)2*2 222 a2 a222 aa2 aab23333 ab23333 b2 b222 ba2 bab23333 $ echo +(a|b)2*a2 a222 aa2 aab23333 ab23333 b2 b222 ba2 bab23333 $ echo @(a|b)2*a2 a222 b2 b222 $ echo !(a|b)2*12 2 222 a12 a222 aa2 aab23333 ab23333 b12 b222 ba2 bab23333
البته توجه دارید که بخش بعد از پرانتز بسته بخشی از glob توسعه یافته نیست و برای هر پنج مورد ثابت است. (بازگشت)