فاصلهها کلمهها را جدا میکنند. در bash،
[سطر جدید]
کاراکتر سمیکالن و سطر جدید دستورات همزمان را از یکدیگر جدا میکنند. از سمیکالن
کاراکتر
یک خط عمودی یا علامت لوله، خروجی یک فرمان را به ورودی فرمان بعدی متصل میکند. همه کاراکترهایی که توسط فرمان اول روانه stdout گردیدهاند، توسط فرمان دوم در stdin قابل خواندن هستند.
یک
یک OR شرطی باعث میشود فقط در صورتی که فرمان اول به پایان برسد و با یک کد عدم موفقیت (هر کد غیر صفر) خارج شود، فرمان دوم اجرا گردد.
'
معنای دستوری تمام کاراکترهای درون رشته را غیرفعال میکند. هر وقت خواستار رشتههای لفظی در کُد خود هستید، پوشاندن آنها در نقلقولهای منفرد روال مناسبی است پس احتمال خطر استفاده اتفاقی کاراکتری که برای Bash معنای دستوری نیز دارد را به وجود نیاورید.
"
معنای دستوری تمام کاراکترها به استثنای بسطها را در رشته غیرفعال میکند. اگر انجام بسط پارامتر یا جایگزینی دستور در رشته را لازم دارید، این شکل را به جای نقلقولهای منفرد به کار ببرید.
یادآوری: اهمیت دارد که همواره بسطهای خود را("$var" یا "$(command)" را در نقلقولهای دوگانه بپوشانید. به این ترتیب، به طور ایمن معنای دستوری کاراکترهایی که ممکن است داخل نتیجه بسط قرار گیرند، غیرفعال میگردد.
برای مثالهایی از ترکیبهای دستوری پایین، بخش مثالهای ساختارهای اصلی را ببینید.
دستورات مرکب جملههایی هستند که میتوانند چندین فرمان را اجرا کنند اما توسط Bash به عنوان یک نوع دستور گروهی در نظر گرفته میشوند.
{
لیست فرمانها را در پوسته جاری همانطور که اگر یک دستور بود، اجرا میکند.
{ cmd1; cmd2; } | cmd3
یا ممکن است بخواهید بعد از یک عملگر || دستورات چندگانه را اجرا نمایید:
rm file || { echo "Removal failed, aborting."; exit 1; }
برای بدنه توابع نیز مورد استفاده است. از نظر تکنیکی، میتواند برای بدنه حلقهها نیز استفاده شود هرچند این مورد فاقد مستندات، غیرقابل حمل است و به طور معمول ما do ...; done را برای این مورد ترجیح میدهیم):
توجه: شما قبل از کلیدواژه } برای بستن لیست، یک کاراکتر ; لازم دارید( یا اینکه باید کلیدواژه در یک سطر جدید باشد.)
(
لیست فرمانها را در یک پوسته فرعی اجرا میکند.
این درست مانند گروهبندی فرمان فوق است، فقط، فرمانها در یک پوسته فرعی اجرا میشوند. هر کُدی که بر محیط تأثیر میگذارد از قبیل تخصیص متغیرها، cd و export و غیره، بر محیط اولیه اسکریپت اثر نمیکند بلکه به داخل پرانتزها محدود میشوند.
توجه: قبل از بستن ) به کاراکتر ; نیاز ندارید.
((
به معنای آن که، رشتهها به عنوان نام متغیرهای عدد صحیح در نظر گرفته میشوند، تمام عملگرها نیز به عنوان عملگرهای محاسباتی تلقی میگردند( از قبیل ++, ==, >, <=, غیره). برای انجام بررسیها بر روی اعداد، همیشه باید از این ترکیب استفاده نمایید!
$((
نتیجه
[[
تمام عملگرهای test پشتیبانی میشوند و همچنین میتوانید
اگر شما در مورد حلقه ها تازه وارد هستید یا خواهان جزئیات و تشریح بیشتر در باره آنها و یا مثالهای کاربرد آنها میباشید، بخش حلقههای شرطی از BashGuide را بخوانید.
do
این ترکیب، یک حلقه واقعی را شکل میدهد که توسط چند دستور بعدی استفاده میشود.
لیست فرمانهای بین do و done دستوراتی هستند که در هر بار تکرار حلقه اجرا خواهند شد.
for
حلقهِ بعد از آن، به ازای هریک از
فرمانهای حلقه با مقداردهی متغیر معین شده در نام با هر یک از کلمات، اجرا خواهد شد.
for ((
حلقهِ بعد از آن، تا موقعی که
while
حلقهِ بعد از آن، تا وقتی که آخرین فرمان اجرا شده از
until
حلقهِ بعد از آن، تا موقعی که آخرین فرمان اجرا شده در
select
حلقهِ بعد از آن، به طور دائم تکرار میشود و به کاربر اجازه میدهد یکی از کلمات داده شده را انتخاب نماید.
دستورات تکرار، با تخصیص کلمه انتخابی کاربر به متغیر معین شده در نام، اجرا میشوند. طبعاً، میتوانید با استفاده از break به این حلقه خاتمه بدهید.
دستورات داخلی فرمانهایی هستند که یک تابع معین تدوین شده در داخل Bash را اجرا مینمایند. به طور قابل فهمی، انها همچنین تنها گونهای از دستورات (متفاوت با موارد فوق) هستند که میتوانند محیط پوسته Bash را ویرایش کنند.
true (یا :)
آنها
false
این دستور یک کد خروج 1 نشان دهنده شکست را برگشت میدهد.
alias
declare (یا typeset)
هر شناسه این دستور یک عبارت تخصیص متغیر جدید است. قسمت قبل از علامت مساوی در هر شناسه، نام متغیر است، و مقدار متغیر بعد از علامت میآید. گزینههای فرمان declar میتوانند برای تعیین نوع متغیر(مانند read-only=فقط خواندنی و export= سراسری و integer= عدد صحیح و array= آرایهای) به کار بروند.
export
این همانند دستور declare -x است. به خاطر داشته باشید که متغیر برای پردازش فرزند، همان متغیری که شما صادر نمودهاید نیست. فقط همان داده را نگهداری میکند. این به معنای آن است که نمیتوانید مقدار آن را تغییر داده و انتظار داشته باشید که در پردازش والد نیز تغییر کند.
local
به محض اینکه تابع خارج میشود، متغیر ناپدید میشود. تخصیص مقدار به آن در تابع نیز، متغیر عمومی با همان نام را، اگر وجود داشته باشد، تغییر نمیدهد. همان گزینههایی که فرمان declare قبول میکند، میتوانند با local به کار بروند.
type
نوع میتواند یا:
read
اگر بیش از یک نام متغیر ارائه شده باشد، سطر خوانده شده با استفاده از کاراکترهای داخل متغیر IFS به عنوان جداکنندهها، تجزیه میشود. اگر تعداد نامهای داده شده کمتر از تکههای جداگانه موجود در سطر باشد، آخرین متغیر تمام دادههای باقیمانده تجزیه نشده را دریافت میکند.
echo
اولین شناسهها میتوانند گزینههایی برای تبدیل وضعیت رفتار خاص باشند(مانند -n اخذ شده از کلمه no newline برای عدم درج سطرجدید در انتها و -e از جمله escape sequences برای ارزیابی رشتههای eacape).
printf
فرمان help printf را ببینید.
pwd
میتوانید برای آنکه pwd از هر لینک نمادین در نام مسیر اجتناب کند، از گزینه -P استفاده نمایید.
cd
command
این دستور به Bash میگوید از جستجو برای یک مستعار، تابع، یا کلمه کلیدی با آن نام چشمپوشی کند، و به جای آن فرض کند نام فرمان یک دستور داخلی یا یک برنامه در PATH میباشد.
.
این گونهای مشابه include در سایر زبانها میباشد. اگر شناسههایی بیش از نام فایل برای source فراهم شده باشد، آنها به عنوان پارامترهای مکانی در جریان اجرای آن کد منبع، تنظیم میشوند. اگر نام فایل برای منبع فاقد
exec
سایر شناسهها، به عنوان شناسههای فرمان عبور داده میشوند. اگرشناسهای برای exec ارائه نگردیده است اما شما
exit
logout
return
درست مانند دستور داخلی exit، ممکن است یک وضعیت خروج با آن تعیین گردد.
ulimit
jobs:
bg
fg
kill
شماره شناسایی پردازش(PID) یا
trap
کُدی که در اولین شناسه تعبیه شده است، هنگامی که یکی از سیگنالهای مشخص شده در هر یک از شناسههای دیگرِ trap دریافت گردد، اجرا میشود.
suspend
بسیار مشابه آن موردی است که موقع رسیدن یک سیگنال
wait
در شناسهها میتوانید jobها (توسط
break
موقعی که بیش از یک حلقه فعال است، خروج غیر عادی از آخرین حلقه تعریف شده صورت میگیرد. وقتی یک
continue
درست مانند break، شاید یک
set
shift
به این ترتیب، کمیتی که در $1 قرار داشت، دور انداخته میشود،مقدار متغیر $2 در $1 قرار میگیرد، کمیت $3 داخل $2 میرود، و به همین ترتیب. میتوانید یک عدد صحیح به عنوان شناسه برای shift تعیین نمایید که مشخص میکند این عمل shift چند مرتبه تکرار بشود.
getopts
getopts اولین شناسه را به عنوان مشخص کننده آن که کدام گزینهها را در شناسهها جستجو کند، به کار میبرد. سپس اولین گزینه در شناسهها را که در این مشخص کننده گزینه، ذکر گردیده (یا اگر getopts از قبل اجرا شده است، دومین گزینه) میگیرد، و این گزینه را در متغیری قرار میدهد که نام آن در دومین شناسه getopts مشخص گردیده است. این فرمان در یک حلقه همیشه به طور بسیار خوشنمایی به کار میرود:
while getopts abc opt do case $opt in a) ...;; b) ...;; c) ...;; esac done
به این طریق همه گزینهها در شناسهها تجزیه میشوند و وقتی آنها یکی از موارد -a، -b یا -c باشند، کُد مربوطه در جمله case اجرا میشود. برای تعیین گزینههای چندتایی در شناسههایی که به getopts داده میشود، این شیوه کوتاه نیز معتبر است: -ac.
اگر شما برای کار با ورودی و خروجی در bash تازه وارد هستید یا در جستجوی مثالها، جزئیات و یا توضیحات بیشتر میباشید، سُراغ خواندن ورودی و خروجی از راهنمای Bash بروید.
Bash برای مدیریت جریانهای داده بین پردازشها یک ابزار بسیار خوب است. در سایه عملگرهای ممتازش برای متصل نمودن توصیفگرهای فایل، ما میتوانیم تقریباً از هرجایی دادهها را دریافت کنیم و تقریباً به هر جایی ارسال کنیم. فهم و دریافت جریانها و چگونگی دستکاری آنها در bash، کلیدی برای وسعت قدرت bash است.
یک توصیفگر فایل مشابه جادهای میان یک فایل و یک پردازش است. برای ارسال دادهها به فایل یا خواندن دادهها از فایل به وسیله پردازش استفاده میشود. یک پردازش میتواند توصیفگرهایفایل بسیار زیادی داشته باشد، اما به طور پیشفرض، برای وظایف استاندارد، سه توصیفگر وجود دارد.
0
1
2
تغییر مسیر فایل: عملگر >
به طور اختیاری میتوانید عددی را جلوی عملگر > مشخص نمایید. اگر مشخص نکنید،عدد 1 پیشفرض میشود. عدد، نشان میدهد خروجی کدام توصیفگر فایلِ پردازش تغییر مسیر داده شود.
تغییر مسیر فایل: عملگر >>
تغییر مسیر فایل: عملگر <
به طور اختیاری میتوانید در جلوی عملگر < عددی را تعیین نمایید. اگر مشخص نکنید، عدد به پیشفرض 0 تنظیم میشود. این عدد، آن توصیفگرفایلِ پردازش، که تغییر مسیر به آن انجام میشود را نمایان میکند.
تغییر مسیر فایل: عملگر &>
تغییر مسیر فایل: عملگر &>>
Here-String: یک رشته منفرد از دادهها را به
[WORD]
Here-Document: سطرهای دادهها را به
توجه: کلمه بعد از <<
توجه: شما میتوانید کلمه پس از << را 'نقلقولی' نمایید. اگر چنین کنید، هر موردی که در سطرهای دادهها مانند بسطها باشد، توسط bash بسط نخواهد یافت.
لوله: عملگر |
لوله: عملگر |&
جایگزینی فرمان: خروجی فرمان را ضبط میکند و آنرا در جا بسط میدهد.
ما فقط موقعی از جایگزینی فرمان داخل فرمانهای دیگر استفاده میکنیم، که میخواهیم خروجی یک فرمان بخشی از یک دستور دیگر بشود. یک ترکیب جایگزین کهنه و نابخردانه برای جایگزینی فرمان، نقلقول-وارونه است: `command`. این ترکیب همان نتیجه را دارد، اما پوشش مناسبی نیست و به آسانی هم با نقلقولها اشتباه میشود( نقلقول-وارونه، هیچ ارتباطی به نقلقول کردن ندارد!). از این ترکیب اجتناب نمایید و موقعی که با آن مواجه میشوید، آن را با ترکیب $(command) تعویض کنید.
این مانند اجرای فرمان دوم، گرفتن خروجی آن، و درج آن خروجی در جایی که شما $(...) را گذاشته بودید، است.
جایگزینی پردازش: عملگر <(...) به یک فایل جدید تولید شده توسط bash که محتوی خروجی command list است، بسط مییابد.
مانند تغییر مسیر خروجی فرمان دوم به فایلی به نام foo، و آنوقت اجرای فرمان اول با foo به عنوان
توجه: این مورد را با تغییر مسیر فایل اشتباه نکنید. در اینجا < به معنی
جایگزینی پردازش: عملگر >(...) به یک فایل جدید تولید شده توسط bashبسط مییابد، این فایل دادههایی که شما در آن مینویسید را به
این ترکیب مشابه تغییر مسیر فایلی به نام foo به ورودی فرمان دوم، و سپس اجرای فرمان اول با استفاده از foo به عنوان
تغییر مسیر فایل و جایگزینی پردازش: قسمت <(...) با یک فایل تولید شده توسط bash تعویض میگردد، و عملگر < آن فایل جدید را میگیرد و به
این مورد تقریباً با لولهکشی فرمان دوم به فرمان اول یکسان است (secondcommand | firstcommand)، اما فرمان اول آنطور که در یک لوله انجام میشود، در پوسته فرعی اجرا نمیشود. این ترکیب اکثراً موقعی که نیاز داریم فرمان اول محیط پوسته را ویرایش کند(که اگر فرمان در پوسته فرعی قرار گیرد، غیر ممکن میشود)، به کار میرود. برای مثال، خواندن در یک متغیر: read var < <(grep foo file). این کُد کار نمیکند: grep foo file | read var، زیرا var فقط در پوسته فرعی کم دوام، تخصیص خواهد یافت، و به محض اینکه لوله انجام میشود، ناپدید خواهد شد.
توجه:
Here-String و جایگزینی فرمان: بخش $(...) با خروجی فرمان دوم تعویض میگردد، و عملگر <<< آن رشته را به
این تقریباً همان فرمان فوق، با اثر جانبی کوچکی است که $() تمام سطرهای جدید دنباله را از خروجی حذف میکند و <<< یکی به انتهای آن اضافه میکند.
اگر در bash تازه وارد هستید، و کاملاً درک نمیکنید که فرمانها و کُدهای خروج چه هستند یا خواهان برخی جزئیات، توضیح و یا مثالهای بررسیها در آزمایش فرمانها، رشتهها یا فایلها میباشید، سراغ خواندن بخش بررسیها و شرطیها در راهنمای Bash بروید.
یک
if
فرمان if بررسی میکند که آیا آخرین فرمان از اولین
اگر چنین باشد،
while
تکرار بعدی را بر اساس کد خروج آخرین فرمان از
اینها را قبلاً بحث کردهایم، اما تکرار آنها در این بخش با ارزش است، چون در واقع آنها(while و until) همان کار دستورif را انجام میدهند، به استثنای آن که یک حلقه را تا وقتی که کد خروج بررسی شده به ترتیب 0 یا غیر-0 باشد، تکرار میکنند.
Bash دو نوع از الگوها را میشناسد.
اگر در bash تازه وارد هستید یا برخی جزئیات، توضیحات و یا مثالهای از انطباق الگو را میخواهید، بخش الگوها در BashGuide را بخوانید.
?
*
[
[abc]
[a-c]:
بر هر کاراکتر میان(مشمول) a تا c منطبق میگردد. بنابراین درست مانند مثال فوق است.
[!a-c] یا [^a-c]
بر هر کاراکتری که a، یا b یا c نیست، منطبق میشود. به معنی هر حرف دیگر، بلکه همچنین یک عدد، یک نقطه، کاما، یا هر کاراکتر دیگری که فکر کنید، میباشد.
[[:digit:]]: [:
alnum, alpha, ascii, blank, cntrl, digit, graph, lower, print, punct, space, upper, word, xdigit
case
اگر میخواهید یک رشته معین را که میتواند با یکی از چند الگوی جانشین(glob) مختلف منطبق گردد بررسی نمایید، استفاده از case سودمند است.
[[
بررسی آنکه آیا
[ و test فرمانهایی هستند که غالباً در اسکریپتهای sh برای انجام دادن این بررسیها میبینید. [[ تمام این موارد را میتواند انجام بدهد(بلکه بهتر و مطمئنتر) وعلاوه براین انطباق
از [ یا test در کد bash استفاده نکنید. همواره به جای آن، [[ را به کار ببرید. دارای سودمندیهای بسیار و بی کم و کاست است.
از [[ برای انجام تستها بر روی
[[یک گروه دیگر از تستها را میتواند انجام بدهد، ازقبیل بررسی فایلها. help test را برای تمام انواع بررسیهایی که میتواند برایتان انجام بدهد، ببینید.
((
این کلمهکلیدی مخصوص انجام عملیات و بررسیهای عددی است.
عبارت محاسباتی را ببینید
آنچه Bash برای ذخیره دادههای اسکریپت شما در آنها به کار میبرد، پارامترها هستند.
هر پارامتری که شما ایجاد میکنید، متغیر خواهند بود، چون پارامترهای خاص، پارامترهای فقطخواندنی هستند که توسط Bash مدیریت میشوند. یادآوری میشود، شما از نامهای با حروف کوچک برای پارامترهای خود استفاده کنید به طوری که آنها با نامهای تماماً با حروف بزرگ که توسط Bash برای متغیرهای داخلی و متغیرهای محیط به کار میبرد، اشتباه نشوند. همچنین یادآوری میگردد، شما از نامهای پاکیزه و شفاف برای متغیرهایتان استفاده کنید. از x، یا i، یا t، tmp، foo، وغیره اجتناب نمایید. در عوض، نام متغیری به کار ببرید که نوع دادهای را که انتظار میرود متغیر نگهداری کند وصف نماید.
اهمیت دارد که شما ضرورت نقلقول کردن را درک نمایید. به بیان کلی، هر وقت شما یک پارامتر به کار میبرید، باید آن را اینطور نقلقولی کنید: echo "The file is in: $filePath". اگر نکنید، bash محتویات پارامتر شما را به پارههایی چاک میدهد، فضاهای سفید را از آن حذف میکند، و پارهها را به عنوان شناسه به فرمان تغذیه میکند. بله، Bash به طور پیش فرض بسط های پارامتر شما را معیوب میکند - این کار
آخرین اما نه کوچکترین: به یاد داشته باشید که در bash پارامترها
اگر میخواهید از تایپ مجدد همان فرمان در چندین نوبت، پرهیز کنید، یا مدیریت سطرفرمان دستورتان را یک مرحلهای کنید، به جای آن از یک
اگر در استفاده از bash تازه وارد هستید یا خواهان تفصیل و توضیح، ویا مثالهایی از پارامترها میباشید به خواندن بخش پارامترهای خاص در راهنمای BashGuide بپردازید.
1, 2, ...
موقعی که اسکریپت شما به صورت ./script foo bar اجرا گردد، "$1"، میشود "foo" و "$2" نیز "bar" خواهد شد. یک اسکریپت اجرا شده به صورت ./script "foo bar" hubble پارامتر "$1" را به "foo bar" و "$2" را به "hubble" بسط میدهد.
*
اجمالاً، "$*" همان "$1x$2x$3x$4x..." است که در آن x اولین کاراکتر محتوای متغیر IFS است.
با یک IFS پیش فرض، آن عبارت، به صورت "$1 $2 $3 $4 ..." ساده خواهد شد.
@
بنابراین اساساً، "$@" همانند "$1" "$2" "$3" ... است که همگی به طور جداگانه نقلقولی شدهاند.
توجه: شما همواره باید از "$@" بیشتر از "$*"، استفاده کنید به علت آنکه "$@"، واقعیت آنکه هر شناسه یک هویت جداگانه است را حفظ میکند. با "$*"، شما این سوابق را از دست میدهید! "$*" در حقیقت تنها در صورتی سودمند است که شما بخواهید شناسهها را با کاراکتری غیر از فاصله، به عنوان نمونه یک کاما، جدا کنید:
(IFS=,; echo "You ran the script with the arguments: $*") -- تمام شناسههای شما را به صورت جدا شده با کاراکترهای کاما بیرون میدهد.
#
در یک اسکریپت اجرا شده با ۵ شناسه، پارامتر "$#" به 5 بسط مییابد. معمولاً این پارامتر فقط برای بررسی آنکه آیا شناسههایی برای اسکریپت فراهم شده است، سودمند است:
if (( ! $# )); then echo "No arguments were passed." >&2; exit 1; fi
?
ما از $? اکثراً موقعی استفاده میکنیم که بخواهیم کد خروج یک فرمان را در چند محل به کار ببریم، یا از آن برای بررسی در برابر چندین کمیت ممکن در یک جمله case استفاده کنیم.
-
برای یک توضیح در مورد اینکه گزینه-پرچم ها چیستند، کدام موجود میباشند، و چه معنی میدهند،
$
اکثراً برای ایجاد یک فایل PID جهت پردازش bash شما قابل استفاده است (echo "$$" > /var/run/foo.pid)، به این ترتیب، به عنوان مثال به آسانی میتوانید آن را از پردازش bash دیگری خاتمه بدهید.
!
در اسکریپت Bash خود از این پارامتر برای مدیریت فرمانهای پسزمینه استفاده نمایید:
foo ./bar & pid=$!; sleep 10; kill "$pid"; wait "$pid"
_
این یکی اکثراً در پوستههای محاورهای جهت کمی کوتاه نمودن تایپ، به کار میرود:
mkdir -p /foo/bar && mv myfile "$_"
اگر در استفاده از bash تازه وارد هستید یا خواهان تفصیل و توضیح، ویا مثالهایی از عملیات پارامتر میباشید به خواندن بخش بسط پارامتر راهنمای BashGuide و پرسش و پاسخ شماره73 بپردازید.
"$var" و "${var}"
به کمیت قرار گرفته در داخل پارامتر var بسط مییابد. ترکیب بسط پارامتر با محتویات متغیر تعویض میگردد.
"${var:-Default Expanded Value}"
به کمیت داخل پارامتر var یا اگر رشته var تهی باشد به Default Expanded Value(کمیت پیشفرض بسط) بسط مییابد . برای بسط به یک کمیت پیشفرض در حالتی که محتوای پارامتر تهی باشد (تنظیم نشده یا محتوی هیچ کاراکتری نباشد)، از این بسط استفاده کنید.
"${var:=Default Expanded And Assigned Value}"
به کمیت احاطه شده در داخل پارامتر var بسط مییابد، اما اگر پارامتر تهی باشد، ابتدا قسمت «کمیت پیشفرض بسط و تخصیص»(Default Expanded And Assigned Value) را به پارامتر تخصیص میدهد. این ترکیب دستوری غالباً با فرمان کولن (:) به کار میرود: : "${name:=$USER}"، اما تخصیص عبارت منظم نیز با مورد فوق به خوبی کار میکند: name="${name:-$USER}".
"${var:?Error Message If Unset}", "${name:?Error: name is required.}"
به کمیت داخل پارامتر name بسط مییابد، یا اگر این پارامتر تهی باشد پیغام خطای بعد از ? را نمایش میدهد. اسکریپت(یا اگر در یک پوسته محاورهای باشد، تابع) لغو میگردد.
${name:+Replacement Value} و ${name:+--name "$name"}
اگر پارامتر name تهی نباشد به رشته داده شده بسط مییابد. این بسط اساساً برای بسط دادن پارامتر همراه مقداری متن به کار میرود. مثال، دو پارامتر را بسط میدهد: توجه کنید چطور برخلاف تمام مثالهای دیگر، بسط اصلی، به منظور مجاز نمودن تفکیک کلمه رشته داخلی، نقلقولی نیست. با وجود این، نقلقول پارامتر در رشته داخلی را به خاطر داشته باشید!
"${line:5}" و "${line:5:10}" و "${line:offset:length}"
یک زیر رشته از کمیت نگهداری شده در داخل پارامتر line را بسط میدهد. زیر رشته از کاراکتر شماره 5 (یا عدد نگهداری شده در داخل پارامتر offset، در مثال سوم) شروع میشود و طولی برابر 10 کاراکتر(یا عدد نگهداری شده در داخل پارامتر length) دارد. offset از 0 شمارش میشود. اگر طول از قلم افتاده باشد، زیررشته تا انتهای کمیت پارامتر امتداد مییابد.
"${@:5}" و "${@:2:4}" و "${array:start:count}"
عناصر یک آرایه را باشروع از یک شاخص start و تمام یا یک تعداد معلوم count از عناصر بسط میدهد. تمام عناصر به صورت شناسههای جداگانه بسط داده میشوند. اگر از @ به عنوان نام پارامتر استفاده نمایید، به علت وجود نقلقولها عناصر از پارامترهای مکانی اخذ میشوند (در دومین نمونه، شناسههای اسکریپت شما عبارت میشوند از: "$2" "$3" "$4" "$5").
"${!var}"
کمیت پارامتر نامبرده در محتوای پارامتر var را بسط میدهد. این تکنیک نامناسبی است! این بسط، کد شما را در آینده بسیار غیرشفاف و غیرقابل پیشبینی، میسازد. احتمالاً شما به جای آن یک آرایه انجمنی لازم دارید.
"${#var}" و "${#myarray[@]}"
به طول کمیت داخل پارامتر var بسط مییابد. نمونه دوم به تعداد عناصر آرایهای به نام myarray بسط مییابد.
"${var#A Prefix}" و "${PWD#*/}" و "${PWD##*/}"
به کمیت نگهداری شده در داخل پارامتر var پس از حذف رشته A Prefix از ابتدای آن، بسط مییابد. اگر کمیت شامل prefix(پیشوند) داده شده نباشد، به خود کمیت، بسط مییابد. پیشوند میتواند الگوی glob نیز باشد، که در آن حالت رشتهای که با الگو تطبیق نماید، ازابتدای کمیت حذف میشود. میتوانید علامت # را برای حریص نمودن الگوی انطباق، دوتایی کنید.
"${var%A Suffix}" و "${PWD%/*}" و "${PWD%%/*}"
به کمیت نگهداری شده در داخل پارامتر var پس از حذف رشته A Suffix از انتهای آن، بسط مییابد. درست مانند عمل کوتاه سازی پیشوند، کار میکند، فقط از انتها جدا میکند.
"${var/pattern/replacement}" و "${HOME/$USER/bob}" و "${PATH//:/ }"
به کمیت نگهداری شده داخل پارامتر var پس از تعویض الگوی معین(pattern) با رشته جایگزین تعیین شده(replacment) بسط مییابد. الگو یک glob است که برای جستجوی رشته به منظور تعویض کمیت داخل var به کار میرود. اولین مورد تطابق، با رشته جایگزین تعویض میگردد. میتوانید کاراکتر / نخست را برای تعویض تمام موارد انطباق، دوتایی کنید: نمونه سوم معادل محتوای PATH است که تمام کاراکترهای کولن در داخل آن با فاصله تعویض گردیده باشد.
"${var^}" و "${var^^}" و "${var^^[ac]}"
کمیت نگهداری شده در پارامتر var را بعد از تبدیل تمام کاراکترهای منطبق با الگو به حروف بزرگ، بسط میدهد. الگو
"${var,}" و "${var,,}" و "${var,,[AC]}"
کمیت نگهداری شده در پارامتر var را بعد از تبدیل تمام کاراکترهای مورد تطبیق با الگو، به حروف کوچک بسط میدهد. درست مانند عملیات تبدیل به حروف بزرگ، کار میکند، فقط موارد انطباق را به حروف کوچک تبدیل میکند.
آرایهها متغیرهایی هستند که حاوی رشتههای متعدد میباشند. هرگاه به ذخیره اقلام چندگانه در یک متغیر نیاز دارید، از یک آرایه استفاده کنید ، نه از متغیر رشتهای. آرایهها امکان نگهداری مطلوب عناصر جداگانه را برای شما فراهم میکنند و به شما اجازه میدهند عناصر را به طور پاکیزه در شناسههای جداگانه بسط بدهید. اگر شما اقلام خود را با یکدیگر در یک رشته درهم بر هم نمایید، انجام این کار غیر ممکن است!
اگر شما در bash تازه وارد هستید یا به طور کامل نمیدانید آرایهها چه هستند و چرا از کاربرد آنها نسبت به متغیرهای معمولی پشتیبانی میشود، یا جویای توضیحات بیشتر و یا مثالهای آرایهها هستید، به خواندن بخش آرایهها در راهنمای BashGuide و پرسش و پاسخ شماره ۵ بپردازید.
myarray=( foo bar quux )
یک آرایه به نام myarray که شامل سه عضو است ایجاد میکند. آرایهها با استفاده از ترکیب x=(y) ایجاد میگردند وعناصر آرایه با فضای سفید از یکدیگر جدا میشوند.
myarray=( "foo bar" quux )
آرایه myarray را که شامل
myfiles=( *.txt )
یک آرایه myfiles ایجاد میکند که شامل نام تمام فایلهای دایرکتوری جاری که به پسوند .txt ختم میگردند خواهد بود. از هر نوع بسط میتوانیم در ترکیب تخصیص آرایه استفاده نماییم. این مثال از بسط نام مسیر برای تعویض الگوی جانشین با تمام نام فایلهایی که با آن منطبق میشوند، استفاده میکند. وقتی تعویض انجام شد، تخصیص آرایه مانند دو مثال اول صورت میگیرد.
myfiles+=( *.html )
تمام فایلهای HTML از دایرکتوری جاری را به آرایه myfiles اضافه میکند. ترکیب دستوری x+=(y) به همان روش تخصیص معمولی آرایه میتواند به کار برود، اما عناصر را به انتهای آرایه الحاق میکند.
names[5]="Big John" و names[n + 1]="Long John"
یک رشته را به عضوی از آرایه که دارای یک شاخص معین است تخصیص میدهد. با استفاده از این ترکیب، شما به طور صریح به Bash میگویید که میخواهید مقدار رشته را در کدام عضو ذخیره کند. شاخص در واقع به عنوان یک
read -ra myarray
یک سطر را به فیلدها میشکند و فیلدها را در یک آرایه به نام myarray ذخیره میکند. فرمان read یک سطر را از
IFS=, read -ra names <<< "John,Lucas,Smith,Yolanda"
یک سطر را با استفاده از , به عنوان جداکننده، به فیلدها میشکند و فیلدها را در آرایهای به نام names ذخیره میکند. ما از عملگر <<< برای تغذیه یک رشته به
IFS=$'\n' read -d '' -ra lines
تمام سطرها را از
files=(); while IFS= read -d '' -r file; do files+=("$file"); done < < (find . -name '*.txt' -print0)
به طور مطمئن تمام فایلهای TXT محتوای دایرکتوری جاری را به صورت بازگشتی در آرایهای به نام files میخواند.
ما با ایجاد یک آرایه خالی به نام files آغاز میکنیم. سپس یک حلقه while را شروع میکنیم که یک دستور read برای خواندن یک نام فایل از
declare -A homedirs=( ["Peter"]=~pete ["Johan"]=~jo ["Robert"]=~rob )
یک آرایه
homedirs["John"]=~john
یک عنصر را به آرایه انجمنی اضافه میکند، کلید "John" به دایرکتوری خانگی john مسیردهی شده است.
echo "${names[5]}" و echo "${names[n + 1]}"
یک عضو منفرد از یک آرایه را که با شاخص به آن ارجاع شده بسط میدهد. این ترکیب دستوری بازیابی محتوای یک عضو آرایه با استفاده از شاخص آن را برای شما میسر میسازد. شاخص در واقع به عنوان یک
echo "${names[@]}"
هر عضو آرایه را به عنوان یک شناسه جداگانه بسط میدهد. برای بسط آرایهها این روش ارجح است. هر عضو آرایه همان طور که اگر به عنوان یک شناسه جدیدِ نقلقولی شدهِ صحیح عبور داده میشد، بسط مییابد.
cp "${myfiles[@]}" /destinationdir/
تمام فایلهای مورد اشاره توسط نام فایلهای داخل آرایه myfiles را به /destinationdir/(دایرکتوری مقصد)، کپی میکند. بسط یک آرایه با استفاده از ترکیب دستوری "${array[@]}" صورت میگیرد. این نمونه به طور کارآمدی آن ترکیب بسط را با لیستی از تمام عناصر نگهداری شده در آرایه، به صورت نقلقولی شدهِ صحیح، به عنوان شناسههای جداگانه، تعویض میکند.
rm "./${myfiles[@]}"
تمام فایلهای مورد اشاره به وسیله نام فایلهای داخل آرایه myfiles را حذف میکند. به طور کلی پیوست نمودن رشتهها به یک ترکیب بسط آرایه، ایدهای
(IFS=,; echo "${names[*]}")
آرایه names را به یک
for file in "${myfiles[@]}"; do read -p "Delete $file? " && [[ $REPLY = y ]] && rm "$file"; done
تکرار روی تمام عناصر آرایه myfiles پس از بسط آنها به داخل جمله for انجام میشود. آنوقت برای هر فایل، از کاربر سؤال می کند که آیا میخواهد فایل را حذف کند.
for index in "${!myfiles[@]}"; do echo "File number $index is ${myfiles[index]}"; done
تکرار روی تمام شاخصهای آرایه myfiles پس از بسط آنها به درون جمله for انجام میشود. ترکیب "${!array[@]}" (به ! توجه کنید) به لیستی از
names=(John Pete Robert); echo "${names[@]/#/Long }"
عمل بسط پارامتر را روی هر عنصر آرایه names انجام میدهد. موقع اضافه کردن یک عمل بسط پارامتر به یک بسط آرایه، عمل بسط پارامتر بر هر عضو منفردی که بسط داده میشود، اعمال میگردد.
names=(John Pete Robert); echo "${names[@]:start:length}"; echo "${names[@]:1:2}"
به تعداد length عنصر آرایه را با شروع از شاخص start بسط میدهد. مشابه بسط "${names[@]}" اما
printf '%s\n' "${names[@]}"
هر عضو آرایه را در یک سطر جدید بیرون میدهد. این دستور printf تکنیک بسیار مفیدی برای بیرون دادن عناصر آرایه به یک روش متعارف است(در این مورد، پیوست کردن سطر جدید به هر یک). قالب دهنده رشته فراهم شده برای printf بر هر عضو اِعمال میگردد( البته، جز اینکه چند %s در آن ظاهر شود).
for name in "${!homedirs[@]}"; do echo "$name lives in ${homedirs[$name]}"; done
تکرار روی تمام عناصر آرایه homedirs بعد از بسط آنها به داخل جمله for، انجام میشود. ترکیب دستوری برای به دست آوردن کلیدهای آرایههای انجمنی همانند آن ترکیب برای آرایههای معمولی است. به جای اعداد با شروع از 0، اکنون کلیدهایی را به دست میآوریم که برای کمیتهای آرایه انجمنی تعیین کردهایم. بعداً میتوانیم از این کلیدها برای مراجعه به کمیتهای داخل آرایه استفاده کنیم، درست مانند آرایههای معمولی.
printf '%s\n' "${#names[@]}"
تعداد عناصر آرایه را بیرون میدهد. در این دستور printf، نتیجه بسط صرفنظر از تعداد عناصر آرایه، تنها یک شناسه خواهد بود. شناسه بسط یافته، یک عدد بیانگرِ تعداد عناصر آرایه names میباشد.
[[ $1 ]] || { echo "You need to specify an argument!" >&2; exit 1; }
ما در اینجا یک فرمان گروهی به کار میبریم زیرا عملگر || فقط یک فرمان میپذیرد.
ما میخواهیم هر دو فرمان echo و exit در صورت تهی بودن $1 اجرا گردند.
(IFS=','; echo "The array contains these elements: ${array[*]}")
در اینجا از پرانتزها برای راهاندازی یک پوسته فرعی استفاده میکنیم.
ما میخواهیم متغیر IFS را تنظیم کنیم، به این طریق IFS فقط در پوسته فرعی تغییر خواهد نمود نه در اسکریپت اصلی . این امر ما را از لزوم تنظیم مجدد آن به مقدار پیش فرض، بعد از بسط در دستور echo معاف میکند (که در غیر اینصورت مجبور میشدیم برای اجتناب از رفتار غیر منتظره بعدی، این کار را انجام بدهیم).
(cd "$1" && tar -cvjpf archive.tbz2 .)
در اینجا برای تغییر موقتی دایرکتوری کاری به آنچه در $1 قرار دارد، از یک پوسته فرعی استفاده میکنیم.
بعد از انجام عملیات tar (موقعی که پوسته فرعی به پایان میرسد)، به جایی که قبل از فرمان cd بودیم، باز میگردیم زیرا دایرکتوری کاری اسکریپت اصلی هرگز تغییر نمیکند.
((completion = current * 100 / total))
توجه نمایید که زمینه محاسباتی، نسبت به دستورات عادی bash از قواعد تجزیه کاملاً متفاوتی پیروی میکند.
[[ $foo = /* ]] && echo "foo contains an absolute pathname."
میتوانیم از کلیدواژه [[ برای انجام تمام تستهایی که فرمان test(1) قادر به انجام است، استفاده کنیم.
اما به طوری که در مثال نشان داده شده، این فرمان موارد بیشتری همچون مطابقت الگوی جانشین، انطباق عبارت منظم، تست گروهی و غیره را میتواند انجام بدهد.
for file in *.mp3; do openssl md5 "$file"; done > mysongs.md5
حلقه for روی تمام شناسههای بعد از کلمه کلیدی in تکرار میشود.
هر شناسه به تنهایی در متغیری به نام file قرار گرفته و بدنه حلقه اجرا میشود.
خروجی یک فرمان را کورکورانه به for عبور ندهید!
for روی کلماتی از خروجی دستور تکرار خواهد شد، که تقریباً هرگز آنچه واقعاً میخواهید، نیست!
for file; do cp "$file" /backup/; done
این نگارش فشرده حلقه for با پارامترهای مکانی تکرار میشود.
مورد فوق در اصل معادل for file in "$@" است.
for (( i = 0; i < 50; i++ )); do printf "%02d," "$i"; done
یک لیست از اعداد دورقمی شده با صفر مقدم، که با کاما جدا شدهاند تولید میکند.
while read _ line; do echo "$line"; done < file
این حلقه while تا موقعی که فرمان read موفق است، ادامه مییابد.
(یعنی،تا موقعی که سطرها میتوانند از فایل خوانده شوند). اساساً این مثال، ستون اول دادههای فایل را دور انداخته، بقیه را چاپ میکند.
until myserver; do echo "My Server crashed with exit code: $?; restarting it in 2 seconds .."; sleep 2; done
این حلقه، هر دفعه که myserver با یک کد خروج عدم موفقیت خارج میشود آن را دوباره راهاندازی (restart) میکند.
فرض میکند وقتی myserver با کد خروج ناموفق، خارج میشود، در اثر خرابی است و لازم است راهاندازی مجدد بشود، و اگر با یک کد خروج موفقیت خارج شود، شما فرمان خاموشی(shutdown) به آن دادهاید و نباید مجدداً راهاندازی گردد.
select fruit in Apple Pear Grape Banana Strawberry; do (( credit -= 2, health += 5 )); echo "You purchased some $fruit. Enjoy!"; done
برنامه سادهای که امتیازها را به تندرستی تبدیل میکند.
سرگرمی.
while true; do ssh lhunath@lyndir.com; done
اتصال مجدد در صورت خرابی.
alias l='ls -al'
یک مستعار به نام l میسازد که با ls -al جایگزین میگردد.
مفید برای به سرعت دیدن محتویات دایرکتوری با جزئیات.
declare -i myNumber=5
تعریف یک متغیر صحیح myNumber با ارزشگذاری آن به مقدار 5.
export AUTOSSH_PORT=0
صادر کردن متغیری به نام AUTOSSH_PORT در محیط پردازش bash که به هر پردازش فراخوانی شده توسط این پردازش bash به ارث میرسد.
foo() { local bar=fooBar; echo "Inside foo(), bar is $bar"; }; echo "Setting bar to 'normalBar'"; bar=normalBar; foo; echo "Outside foo(), bar is $bar"
یک تمرین در حوزه متغیر.
if ! type -P ssh >/dev/null; then echo "Please install OpenSSH." >&2; exit 1; fi
کنترل برای دیدن آن که ssh در دسترس است.
در صورتیکه نیست، پیشنهاد نصب
read firstName lastName phoneNumber address
خواندن دادهها از یک سطر منفرد با چهار فیلد به درون چهار متغیر نامبرده.
echo "I really don't like $nick. He can be such a prick."
بیرون دادن یک رشته ساده در خروجی استاندارد.
printf "I really don't like %s. He can be such a prick." "$nick"
همان کار با استفاده از printf به جای echo، تفکیک متن و داده به طور مطلوب.
cd ~lhunath
تغییر دایرکتوری جاری به شاخه خانگی lhunath.
cd() { command cd "$@" && echo "$PWD"; }
داخل تابع، فرمان داخلی cd اجرا میگردد، نه تابع(که باعث بازگشت نا محدود خواهد شد) و اگر موفق شود، دایرکتوری کاری جدید را به خارج echo میکند.
source bashlib; source ./.foorc
تمام کدهای bash داخلِ فایلی به نام bashlib که در جایی از PATH وجود دارد را اجرا میکند، سپس همان کار را با فایل .foorc در دایرکتوری جاری انجام میدهد.
exec 2>/var/log/foo.log
از این پس تمام خروجی خطای استاندارد را به یک فایل ثبت رخداد ارسال میکند.
echo "Fatal error occurred! Terminating!"; exit 1
یک پیغام خطا نمایش داده و از اسکریپت خارج میشود.
BashSheet (آخرین ویرایش 2013-09-13 18:33:07 توسط Lhunath)