بدون چون و چرا شما باید از اینکه Bash چگونه فرمانهای شما را میخواند و آنها را به کُد قابل اجرا تجزیه میکند،، درک مناسبی داشته باشید. دانستن آنکه Bash چطور با کُد شما کار میکند، کلید نوشتن کُدی است که در Bash به خوبی کار کند.
مرحله 1: خواندن دادهها برای اجرا.
Bash همیشه اسکریپت یا فرمان شما در اعلان فرمان bashرا سطر به سطر میخواند. اگر سطر شما با یک کاراکتر
مرحله ورودی:
echo "What's your name?" read name; echo "$name"
مرحله خروجی:
echo "What's your name?"
و
read name; echo "$name"
مرحله 2: پردازش نقلقولها.
یکبار که Bash سطر دادههای شما را خواند، برای یافتن نقلقولها به دقت آن را نگاه میکند. اولین نقلقولی که پیدا میکند یک وضعیت نقلقولی را تا رسیدن به نقلقول بعدی از همان نوع، برای تمام کاراکترهای پس از آن راهاندازی میکند. اگر وضعیت نقلقولی با نقلقول دوگانه راهاندازی گردد ("...")، تمام کاراکترها غیر از $ و " و \ هر گونه معنای خاصی را که ممکن است داشته باشند از دست میدهند. این مطلب نقلقولهای منفرد، فاصلهها و سطرجدید و غیره را شامل میگردد. اگر حالت نقلقولی با نقلقول منفرد راهاندازی گردیده باشد ('...')، تمام کاراکترها به استثنای ' معنای ویژه خود را از دست میدهند. بله، $ و \ نیز به همچنین. بنابراین، فرمان پایین خروجی لفظی ارائه خواهد نمود:
$ echo 'Back\Slash $dollar "Quote"' Back\Slash $dollar "Quote"واقعیت آنکه
$ echo 'Don\'t do this' >
Bash از شما سطر بعدی ورودی را درخواست میکند زیرا برخلاف آنچه ما گمان میکردیم، نقلقول دوم، آنکه ما سعی کردیم با کاراکتر گریز
مرحله ورودی:
echo "What's your name?"
مرحله خروجی:
echo What's your name?
(
مرحله 3: تفکیک دادههای خوانده به دستورات.
اکنون سطر ما با استفاده از ;، و &، به عنوان جدا کننده فرمان به فرمانهای جداگانه تجزیه گردیده است. از مرحله قبل به یاد داشته باشید که هر کاراکتر ; که نقلقولی یا معاف شده بود، دیگر معنی ویژهاش را ندارد و برای تفکیک دستور استفاده نخواهد شد. آنها به صورت لفظی در سطر فرمان حاصله ظاهر خواهند شد:
$ echo "What a lovely day; and sunny, too!" What a lovely day; and sunny, too!
مرحله ورودی:
read name; echo $name
مرحله خروجی:
read name
و
echo $name
مراحل زیر برای هر فرمان حاصل شده از تفکیک سطر دادهها، اجرا میگردد:
مرحله 4: تجزیه عملگرهای خاص.
نگاه کردن دقیق به هر فرمان برای دیدن آنکه آیاعملگرهای خاصی از قبیل {..}، <(..)، < ...، <<< ..، .. | ..، و غیره وجود دارد. تمام اینها با ترتیب مخصوصی پردازش میشوند. عملگرهای تغییر مسیر از سطر فرمان حذف میشوند، سایر عملگرها با عبارت نتیجه شده از آنها جایگزین میشوند (یعنی {a..c} توسط a b c جایگزین میگردد).
مرحله ورودی:
diff <(foo) <(bar)
مرحله خروجی:
diff /dev/fd/63 /dev/fd/62
(توجه: عملگر <(..) یک پردازش پسزمینه برای اجرای فرمان foo (و یک پردازش نیز برای bar) شروع میکند و خروجی را به یک فایل ارسال میکند. سپس خودش با نام مسیر آن فایل تعویض میشود.)
مرحله 5: انجام بسطها.
Bash عملگرهای بسیاری دارد که با بسط مربوط میشوند. سادهترین اینها $parameter است. علامت دلارِ دنبال شده با نام یک پارامتر، که به طور اختیاری شاید با ابروها احاطه شده باشد، بسط پارامتر نامیده میشود. اساساً آنچه Bash اینجا انجام میدهد، فقط تعویض عامل بسط پارامتر با محتویات آن پارامتر است. به همین جهت، فرمان echo $USER در این مرحله به echo lhunath تبدیل خواهد شد. سایر بسطها شامل بسط نام مسیر (echo *.txt)، جایگزینی فرمان (rm "$(which nano)")، و غیره میباشند.
مرحله ورودی:
echo "$PWD has these files that match *.txt :" *.txt
مرحله خروجی:
echo /home/lhunath/docs has these files that match *.txt : bar.txt foo.txt
مرحله 6: تفکیک فرمان به نام فرمان و شناسهها.
نام فرمان Bash که باید اجرا شود همیشه اولین کلمه در سطر است. بقیه دادههای فرمان به کلماتی نفکیک میگردند که شناسهها را به وجود میآورند. این فرایند تفکیک کلمه )Word Splitting) نامیده میشود. اساساً Bash سطرفرمان را از جایی که فضای سفید میبیند به قطعهها تقسیم میکند. این فضای سفید کاملاً از بین میرود و قطعهها کلمات نامیده میشوند. فضای سفید در این زمینه یعنی: همه فاصلهها، tabها یا سطرهای جدید که معاف نشدهاند. (فاصلههای معاف شده، از قبیل فاصلههای داخل نقلقولها، معنی ویژه فضای سفیدشان را از دست میدهند و برای تجزیه سطر فرمان به کار نمیروند. آنها به طور لفظی در شناسههای حاصله ظاهر میگردند.) همینطور، اگر نام فرمانی که میخواهید اجرا نمایید یا یکی از شناسههایی که میخواهید به آن عبور بدهید شامل فاصلههایی باشند که شما نمیخواهید bash برای بریدن سطر فرمان به کلمات به کار ببرد، میتوانید از نقلقولها یاکاراکتر
My Command /foo/bar ## .را اجرا خواهد نمود چون اولین کلمه در این سطر فرمان است'My' این فرمانی به نام "My Command" /foo/bar ## .را اجرا خواهد کرد چون فاصله داخل نقلقولها معنای ویژه خود برای تفکیک کلمات را از دست میدهد 'My Command' این فرمانی به نام
مرحله ورودی:
echo "/home/lhunath/docs has these files that match *.txt :" bar.txt foo.txt
مرحله خروجی:
نام فرمان: 'echo'
شناسه 1: '/home/lhunath/docs has these files that match *.txt :'
شناسه 2: 'bar.txt'
شناسه 3: 'foo.txt'
Step 7: Execute the command.
اکنون که فرمان به نام دستور و مجموعهای از شناسهها تجزیه شده است، Bash شناسههای فرمان را با لیست کلماتی که در مرحله قبل تولید شدهاند تنظیم میکند و فرمان را اجرا میکند. اگر نوع فرمان، دستور داخلی یا تابع باشد، فرمان توسط همان پردازش Bash که تمام این مراحل را انجام داد، اجرا میشود. در غیر اینصورت، Bash نخست انشعاب ایجاد خواهد نمود(ایجاد یک پردازش bash جدید)، پردازشهای bash جدید را با تنظیماتی که از تجزیه این فرمان حاصل شده بود(تغییر مسیرها، شناسهها، و غیره) مقدار دهی نموده و فرمان را در پردازش منشعب شده bash (پردازش فرزند) اجرا میکند. والد(آن Bash که این مراحل را انجام داد) برای کامل شدن دستور در پردازش فرزند منتظر میماند.
مرحله ورودی:
sleep 5
باعث میشود:
├┬· 33321 lhunath -bash
│├──· 46931 lhunath sleep 5
بعد از این مراحل، دستور بعدی، یا سطر بعدی پردازش میشود. وقتی که فایل به انتها میرسد(پایان اسکریپت یانشست bash محاورهای بسته شود) bash متوقف میشود وکُد خروج آخرین فرمانی که اجرا شده است را باز میگرداند.
برای یک مثال بیشتر ساده شدهِ پردازش، این صفحه گرافیکی را ببینید.
این مراحل پس از نگاه کردن به آنها از نزدیک، شاید مطابق عقل سلیم به نظر آید، اما اغلب آنها میتوانند به واسطه وضعیتهای خاص، با دریافت شهودی تلاقی کنند. به عنوان یک مثال، اجازه دهید من چند حالتی را برشمارم که در آن وضعیتها اغلب اشخاص در مورد روشی که فکر میکنند bash دستوراتشان را تفسیر خواهد نمود اشتباه میکنند:
start=1; end=5; for number in {$start..$end}: در مرحله 4 بسط ابرو وقوع مییابد در حالیکه، در مرحله 5 بسط پارامتر رخ میدهد. بسط ابرو سعی میکند {$start..$end} را بسط بدهد، اما نمیتواند. این بسط، $start و $end را به عنوان رشته میبیند، نه بسط پارامتر، و رهایشان میکند:
start=1 end=5 for number in {1..5}نتایج مرحله 5:
start=1 end=5 for number in {$start..$end}
و number به جای 1 اکنون {1..5} خواهد شد. خیر بسط ابرو انجام نگردیده است.زیرنویس مترجم
[ $name = B. Foo ]: تفکیک کلمه این مثال را ناموفق میسازد. در این حالت برنامه ([) test چهار شناسه را جستجو میکند. طرف سمت چپ، یک عملگر، طرف سمت راست، و یک ] انتهایی. برای پیبردن به آنکه در این مثال چه چیز اشتباه است، آنطور که Bash انجام میدهد ببینید: جدا کردن فرمان به شناسهها. فرض کنیم name شامل B. Foo است:
یک مشت بیش از چهارتا. لازم است برای آنکه از انجام تفکیک کلمه به موجب فاصله میان B. و Foo پیش گیری گردد، از نقلقولها استفاده کنید. نقلقول کردن B. Foo و $name به طوری که وقتی $name بسط داده میشود، فضای سفید در B. Foo به طور یکسان با آنکه در طرف راست هست رفتار کند. اهمیت دارد که به خاطر بسپارید، مرحله 5 (انجام بسط) قبل از مرحله 6 میآید (تفکیک فرمان به نام فرمان و شناسهها). این به معنای آنست که $name از خُرد شدن نتیجهاش مصون نمیباشد، زیرا خُرد شدن بعد ازاینکه $name با مقدارش در داخل name تعویض میشود، به وقوع میپیوندد.
تجزیه کننده Bash (آخرین ویرایش 2013-07-10 01:58:19 توسط ormaaj)
#-------------- # مرحله4 #-------------- $(بازگشت)start =1 $end =5 $for number in { 1..5} >do > echo$ number >done 1 2 3 4 5 # بسط ابرو انجام شده است $ #-------------- # مرحله5 #-------------- $start =1 $end =5 $for number in {$ start ..$ end } >do > echo$ number >done {1..5} # فقط بسط پارامترها انجام گردیده است و بسط ابرو انجام نشده $