اسکریپتنویسی در Bash بدون درک درست از نحوهی دریافت ورودی و مدیریت آرگومانها، ناقص است. در این درس، تمام ابزارهایی که برای دریافت داده از کاربر و خط فرمان در اختیار داریم را پوشش میدهیم: از دستور read برای گرفتن ورودی تعاملی گرفته تا پارامترهای موقعیتی و پارامترهای ویژهای که Bash در اختیارمان میگذارد، و در نهایت getopts برای پردازش حرفهای آپشنهای خط فرمان.
دستور read — دریافت ورودی از کاربر
دستور read یک built-in در Bash است که متنی را از stdin (ورودی استاندارد) خوانده و آن را به یک یا چند متغیر نسبت میدهد. کاربرد اصلی آن، ساخت اسکریپتهای تعاملی است که از کاربر سؤال میپرسند.
سینتکس پایه
read [options] [var_name ...]
بهطور پیشفرض، read یک خط کامل از ورودی را میخواند و آن را بر اساس IFS (Internal Field Separator) به کلمات جدا میکند. کلمهی اول به اولین متغیر، کلمهی دوم به دومین متغیر، و به همین ترتیب نسبت داده میشود. اگر تعداد کلمات از تعداد متغیرها بیشتر باشد، مابقی به آخرین متغیر اختصاص مییابد. اگر تعداد متغیرها بیشتر باشد، متغیرهای باقیمانده خالی میمانند.
اگر هیچ نام متغیری به read داده نشود، ورودی در متغیر REPLY ذخیره میشود.
گزینههای مهم read
| گزینه | توضیح |
|---|---|
-p PROMPT | نمایش یک پیام (پرامپت) قبل از دریافت ورودی |
-s | حالت silent — کاراکترهای تایپشده در ترمینال نمایش داده نمیشوند (مناسب برای پسورد) |
-n NCHARS | پس از خواندن تعداد مشخصی کاراکتر، بدون نیاز به Enter، بازگردد |
-t TIMEOUT | در صورتی که کاربر طی مدت مشخص (ثانیه) ورودی ندهد، دستور با شکست مواجه شود |
-a ARRAY | کلمات ورودی را بهعنوان اندیسهای یک آرایه ذخیره میکند |
-r | بکاسلش (\) را بهعنوان کاراکتر escape تفسیر نمیکند و آن را بخشی از ورودی در نظر میگیرد |
-d DELIM | بهجای newline، از اولین کاراکتر DELIM بهعنوان پایان خط استفاده میکند |
مثالهای عملی
۱. دریافت یک ورودی ساده:
#!/bin/bash read -p "نام خود را وارد کنید: " name echo "سلام، $name!"
۲. دریافت چندین مقدار در یک خط:
#!/bin/bash read -p "نام و نام خانوادگی: " first_name last_name echo "نام: $first_name" echo "نام خانوادگی: $last_name"
اگر کاربر عبارت Ali Rezaei را وارد کند، first_name مقدار Ali و last_name مقدار Rezaei را خواهد گرفت.
۳. دریافت پسورد (حالت silent):
#!/bin/bash read -s -p "رمز عبور را وارد کنید: " password echo echo "رمز عبور وارد شد."
۴. استفاده از -r برای جلوگیری از تفسیر بکاسلش:
بدون -r، بکاسلشها بهعنوان کاراکتر escape عمل میکنند:
$ read var Hello\ World $ echo $var Hello World
با -r، بکاسلش بهعنوان بخشی از متن حفظ میشود:
$ read -r var Hello\ World $ echo $var Hello\ World
۵. خواندن ورودی از یک رشته (اینجا-داکیومنت یا here-string):
#!/bin/bash read -r line <<< "این یک متن نمونه است" echo "$line"
۶. استفاده از read در حلقه برای پردازش خطبهخط یک فایل:
#!/bin/bash while IFS= read -r line; do echo "خط: $line" done < "/etc/passwd"
پارامترهای موقعیتی (Positional Parameters)
وقتی یک اسکریپت Bash اجرا میشود، آرگومانهای دادهشده به آن در خط فرمان، بهصورت پارامترهای موقعیتی در دسترس هستند. این پارامترها با شمارههای 1 تا 9 قابل ارجاع هستند و برای شمارههای بیشتر باید از آکولاد استفاده کرد: ${10}، ${11} و الی آخر.
-
$1— اولین آرگومان -
$2— دومین آرگومان -
$3— سومین آرگومان -
...
مثال
اسکریپت greet.sh:
#!/bin/bash echo "سلام، $1 عزیز!" echo "شما $2 سال دارید."
اجرا:
$ ./greet.sh علی ۲۵ سلام، علی عزیز! شما ۲۵ سال دارید.
توجه کنید که آرگومانها بر اساس فاصله (whitespace) از هم جدا میشوند. اگر آرگومانی خود شامل فاصله باشد، باید آن را در گیومه قرار دهید:
$ ./greet.sh "علی رضایی" ۲۵ سلام، علی رضایی عزیز! شما ۲۵ سال دارید.
پارامترهای ویژه (Special Parameters)
Bash مجموعهای از پارامترهای ویژه را در اختیار اسکریپتنویس قرار میدهد که هرکدام اطلاعات خاصی دربارهی اسکریپت و محیط اجرا ارائه میدهند.
$@ — تمام آرگومانها بهصورت مجزا
$@ به تمام پارامترهای موقعیتی (از $1 به بعد) گسترش مییابد. وقتی درون گیومهی دوگانه قرار گیرد — یعنی "$@" — هر پارامتر بهعنوان یک کلمهی جداگانه و با حفظ فاصلههای درون آن در نظر گرفته میشود.
#!/bin/bash # script: show_args.sh for arg in "$@"; do echo "آرگومان: $arg" done
اجرا:
$ ./show_args.sh "سلام دنیا" Bash "scripting is fun" آرگومان: سلام دنیا آرگومان: Bash آرگومان: scripting is fun
"$@" همیشه تعداد اصلی آرگومانها را حفظ میکند و امنترین و استانداردترین روش برای ارجاع به تمام آرگومانهاست.
$* — تمام آرگومانها بهصورت یک رشته
$* نیز به تمام پارامترهای موقعیتی گسترش مییابد، اما وقتی درون گیومهی دوگانه قرار گیرد — یعنی "$*" — تمام آرگومانها بهصورت یک رشتهی واحد با کاراکتر جداساز (اولین کاراکتر متغیر IFS) به هم میچسبند.
#!/bin/bash # script: show_star.sh for arg in "$*"; do echo "آرگومان: $arg" done
اجرا:
$ ./show_star.sh "سلام دنیا" Bash "scripting is fun" آرگومان: سلام دنیا Bash scripting is fun
همانطور که میبینید، تمام آرگومانها بهعنوان یک رشتهی واحد در نظر گرفته شدهاند.
| حالت | رفتار |
|---|---|
$@ (بدون گیومه) | هر آرگومان بهعنوان کلمهای جداگانه (subject to word splitting) |
"$@" | هر آرگومان بهعنوان کلمهای جداگانه، با حفظ فاصلههای درون آن — روش ترجیحی |
$* (بدون گیومه) | هر آرگومان بهعنوان کلمهای جداگانه (subject to word splitting) |
"$*" | تمام آرگومانها بهصورت یک رشتهی واحد با جداکنندهی IFS |
تفاوت کلیدی در رفتار با گیومه است.
"$@"ساختار اصلی آرگومانها را حفظ میکند، در حالیکه"$*"آنها را در یک رشته ادغام میکند.
$# — تعداد آرگومانها
$# تعداد پارامترهای موقعیتی (تعداد آرگومانهای دادهشده به اسکریپت) را برمیگرداند.
#!/bin/bash echo "تعداد آرگومانها: $#"
اجرا:
$ ./count.sh a b c تعداد آرگومانها: 3
$? — کد خروج آخرین دستور
$? کد خروج (exit status) آخرین دستور اجراشده در پیشزمینه را برمیگرداند. مقدار 0 به معنای موفقیت و هر مقدار غیرصفر به معنای خطا یا شکست است.
#!/bin/bash ls /non-existent-directory echo "کد خروج: $?"
خروجی:
ls: cannot access '/non-existent-directory': No such file or directory کد خروج: 2
$0 — نام اسکریپت یا شل
$0 به نام شل یا اسکریپت در حال اجرا گسترش مییابد.
#!/bin/bash echo "نام اسکریپت: $0"
اجرا:
$ ./my_script.sh نام اسکریپت: ./my_script.sh
اگر اسکریپت با مسیر کامل اجرا شود، $0 همان مسیر کامل را نشان میدهد.
getopts — پردازش حرفهای آپشنهای خط فرمان
getopts یک built-in در Bash است که برای پردازش آپشنهای خط فرمان (مانند -f، -v، -o value) طراحی شده است. برخلاف دستور خارجی getopt (با حرف t نه ts)، getopts یک دستور داخلی است و نیازی به فراخوانی یک برنامهی خارجی ندارد. getopts در استاندارد POSIX تعریف شده است.
محدودیت مهم:
getoptsاز آپشنهای بلند GNU مانند--helpیا--verboseپشتیبانی نمیکند.
نحوهی کار
getopts در یک حلقهی while فراخوانی میشود و هر بار یک آپشن را از لیست آرگومانها پردازش میکند. وقتی آپشنی برای پردازش باقی نماند، کد خروج FALSE برمیگرداند و حلقه پایان مییابد.
سینتکس
getopts OPTSTRING VARNAME [ARGS...]
-
OPTSTRING — رشتهای که آپشنهای مورد انتظار را مشخص میکند. اگر بعد از یک حرف، دو نقطه (
:) قرار دهید، یعنی آن آپشن یک آرگومان میپذیرد. -
VARNAME — نام متغیری که خودِ آپشن (حرف) در آن ذخیره میشود.
-
ARGS — (اختیاری) لیست آرگومانهایی که باید پردازش شوند. بهطور پیشفرض،
getoptsپارامترهای موقعیتی ("$@") را پردازش میکند.
متغیرهای ضمنی getopts
| متغیر | توضیح |
|---|---|
OPTIND | اندیس آرگومان بعدی که باید پردازش شود. مقدار اولیه 1 است. برای پردازش مجدد باید آن را به 1 بازنشانی کرد. |
OPTARG | اگر آپشن آرگومان داشته باشد، مقدار آن در این متغیر ذخیره میشود. |
OPTERR | اگر 0 باشد، پیامهای خطای getopts نمایش داده نمیشوند. |
حالتهای گزارش خطا
اگر اولین کاراکتر OPTSTRING دو نقطه (:) باشد، getopts در حالت خطای خاموش (silent mode) قرار میگیرد:
| وضعیت | متغیر آپشن (VARNAME) | OPTARG |
|---|---|---|
| آپشن نامعتبر | ? | حرف آپشن نامعتبر |
| آرگومان اجباری مفقود | : | حرف آپشنی که آرگومان ندارد |
در حالت عادی (verbose)، در هر دو حالت خطا، VARNAME مقدار ? میگیرد و پیام خطا چاپ میشود.
مثال کامل
اسکریپتی که از آپشنهای -f (با آرگومان)، -v (بدون آرگومان) و -h (راهنما) پشتیبانی میکند:
#!/bin/bash # فعالسازی حالت خطای خاموش OPTSTRING=":f:vh" file="" verbose=0 while getopts "$OPTSTRING" opt; do case $opt in f) file="$OPTARG" echo "فایل انتخاب شده: $file" ;; v) verbose=1 echo "حالت verbose فعال شد" ;; h) echo "استفاده: $0 [-f فایل] [-v] [-h]" exit 0 ;; \?) echo "خطا: آپشن نامعتبر -$OPTARG" >&2 exit 1 ;; :) echo "خطا: آپشن -$OPTARG نیاز به آرگومان دارد" >&2 exit 1 ;; esac done # حذف آپشنهای پردازششده از لیست آرگومانها shift $((OPTIND - 1)) # آرگومانهای باقیمانده (non-option arguments) echo "آرگومانهای باقیمانده: $@"
اجرا:
$ ./script.sh -f myfile.txt -v arg1 arg2 فایل انتخاب شده: myfile.txt حالت verbose فعال شد آرگومانهای باقیمانده: arg1 arg2
$ ./script.sh -h استفاده: ./script.sh [-f فایل] [-v] [-h]
$ ./script.sh -x خطا: آپشن نامعتبر -x
نکات مهم دربارهی getopts
-
getoptsبا مشاهدهی--(دو خط تیره) پردازش را متوقف میکند؛ این یعنی «پایان آپشنها». -
getoptsبا مشاهدهی اولین آرگومان غیرآپشنی (آرگومانی که با-شروع نمیشود و آرگومان یک آپشن نیست) پردازش را متوقف میکند. -
بعد از اتمام پردازش آپشنها، معمولاً از
shift $((OPTIND - 1))برای حذف آپشنهای پردازششده از$@استفاده میشود تا فقط آرگومانهای باقیمانده باقی بمانند. -
آپشنها را میتوان بهصورت ترکیبی نوشت:
-vfمعادل-v -fاست (البته اگر-fآرگومان داشته باشد، باید آخرین آپشن باشد:-vf myfile.txt).
جمعبندی سریع
| ابزار / پارامتر | کاربرد |
|---|---|
read | دریافت ورودی تعاملی از کاربر یا خواندن خط از stdin |
$1, $2, ... | دسترسی به آرگومانهای موقعیتی اسکریپت |
$@ | تمام آرگومانها بهصورت مجزا (روش ترجیحی) |
$* | تمام آرگومانها بهصورت یک رشته (با "$*") |
$# | تعداد آرگومانها |
$? | کد خروج آخرین دستور |
$0 | نام اسکریپت یا شل در حال اجرا |
getopts | پردازش حرفهای آپشنهای خط فرمان (مانند -f value) |
نکتهی نهایی: در ۹۹٪ موارد، برای ارجاع به تمام آرگومانها از
"$@"استفاده کنید. این روش امنترین و قابلپیشبینیترین رفتار را دارد و آرگومانهای دارای فاصله را بهدرستی حفظ میکند.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: منبع مستندات