رفتن به محتوا
LoopX

دستورات Bash: برگه‌ی تقلب اسکریپت‌نویسی

همه‌ی دستورهای دوره‌ی اسکریپت‌نویسی Bash در یک صفحه: ۱۶۳ دستور از ۱۴ درس، به ترتیب درس‌ها. هر دستور در درس خودش با خروجی واقعی اجرا و توضیح داده شده است؛ روی اسم درس بزن تا توضیح کامل و مثال‌ها را ببینی.

مبانی

اولین اسکریپت

دستورکاری که می‌کند
#!/usr/bin/env bashخط اول: اجرا با bash (قابل‌حمل)
chmod +x script.shدادن مجوز اجرا
./script.shاجرای مستقیم (نیاز به x و shebang)
bash script.shاجرا بدون نیاز به x؛ shebang نادیده
source script.sh / . script.shاجرا در همین shell (cd و متغیرها می‌مانند)
# توضیحکامنت؛ تا آخر خط
bash -n script.shبررسی نحو بدون اجرا
exit 3پایان اسکریپت با کد ۳
echo $?کد خروج آخرین دستور
file script.shتشخیص نوع فایل (از روی shebang)
sed -i 's/\r$//' fileتبدیل CRLF ویندوز به LF

متغیرها و نقل‌قول

دستورکاری که می‌کند
name="value"تعریف متغیر (بدون فاصله دور =)
echo "$name"خواندن متغیر، همیشه با کوتیشن دوتایی
echo '$name'متن دقیق، بدون جایگزینی
"${name}_backup"آکولاد برای مشخص‌کردن مرز اسم
today=$(date +%F)خروجی دستور در متغیر
$((a + b)) $((a * b))محاسبه‌ی عدد صحیح
((count++)) ((count += 5))تغییر شمارنده
$((10#$month + 1))محاسبه با عدد دارای صفر اول
date +%F_%H-%M-%Sتاریخ و ساعت برای اسم فایل
readonly PI=3.14 unset nameثابت واقعی / پاک‌کردن متغیر
printf '[%s]\n' $varدیدن اینکه شل متغیر را چند تکه کرد
${dir:?پیام}اگر خالی بود، پیام بده و متوقف شو

ورودی و آرگومان‌ها

دستورکاری که می‌کند
read -r -p "Name: " nameپرسیدن از کاربر
read -s -p "Password: " passخواندن رمز بدون نمایش
read -t 5 var / read -n 1 keyبا زمان‌سنج / فقط یک کاراکتر
read a b rest <<< "x y z w"شکستن یک خط به چند متغیر
echo "$1" ${10}آرگومان اول / آرگومان دهم
echo "$#"تعداد آرگومان‌ها
"$@"همه‌ی آرگومان‌ها، هر کدام جدا
shift / shift 2دور انداختن اولین آرگومان (یا دو تای اول)
if [[ $# -ne 1 ]]; then ... exit 1; fiبررسی تعداد آرگومان (مثال ۶)
echo "Usage: $0 <file>" >&2راهنما روی stderr
name="${1:-World}"مقدار پیش‌فرض برای آرگومان
printf '[%s]\n' "$@"دیدن اینکه هر آرگومان چطور رسید

شرط‌ها

دستورکاری که می‌کند
if [[ -f file ]]; then ... fiاگر فایل معمولی است
if ...; then ... elif ...; then ... else ... fiچند شاخه
[[ $a -gt $b ]]عدد: -eq -ne -lt -le -gt -ge
(( a > b ))مقایسه‌ی عدد با ریاضی
[[ $s == "Ali" ]] [[ -z $s ]]رشته: برابر / خالی
[[ $f == *.txt ]] [[ $d =~ ^[0-9]+$ ]]الگو / regex
[[ -e p ]] [[ -d p ]] [[ -s p ]]وجود / پوشه / غیرخالی
[[ -r p && -w p ]]ترکیب با && (و || و !)
mkdir -p d && cd d / cmd || exit 1اگر موفق شد / اگر شکست خورد
echo $?کد خروج آخرین دستور (۰ = موفق)
if ! grep -q x file; then ...نفی یک دستور
bash -n script.shبررسی نحو پیش از اجرا

case

دستورکاری که می‌کند
case "$1" in start) ... ;; stop) ... ;; *) ... ;; esacساختار کامل
de | at)چند الگو (یا)
*.txt) [0-9]*) ?)الگوهای wildcard
*)پیش‌فرض؛ آخر بنویس
shopt -s nocasematchنادیده‌گرفتن حروف بزرگ و کوچک
shopt -s extglob +([0-9])الگوی «یک یا چند رقم»
;& ;;&ادامه‌ی بی‌قید / آزمون الگوهای بعدی (bash 4+)
command="$1"; shift; case "$command" in ...اسکریپت با زیردستور
kill -0 PIDبررسی زنده‌بودن پروسه (بدون سیگنال)
PS3="Pick: "; select x in a b c; do ...; doneمنوی آماده

حلقه‌ها

دستورکاری که می‌کند
for f in *.log; do ...; doneبرای هر فایل
for i in {1..5}بازه‌ی ثابت (نزولی {5..1}، قدم {0..10..2})
for ((i=1; i<=n; i++)); do ...; doneحلقه‌ی C-style با متغیر
while (( i < 5 )); do ...; doneتا وقتی شرط برقرار است
until [[ -e file ]]; do sleep 1; doneتا وقتی شرط برقرار شود
break / continue / break 2خروج / دور بعد / خروج از دو حلقه
while IFS= read -r line; do ...; done < fileفایل خط‌به‌خط
while read -r a b c; do ...; done < fileشکستن هر خط به فیلد
... done < <(grep x file)حلقه روی خروجی دستور بدون subshell
shopt -s nullglobالگوی بی‌تطابق ← حلقه اجرا نشود
mv -n -- "$f" "$new"تغییر نام بدون رونویسی
timeout 5 commandکشتن دستور بعد از ۵ ثانیه

ساختارمند نوشتن

تابع‌ها

دستورکاری که می‌کند
greet() { echo "Hello, $1"; }تعریف تابع (قبل از استفاده)
greet Aliصدازدن؛ آرگومان‌ها در $1 و $#
x=$(add 2 3)گرفتن خروجی (echo) تابع
is_dir() { [[ -d $1 ]]; } if is_dir x; thenتابع شرط: کد خروج
return 3 / exit 1برگشت از تابع / بستن کل اسکریپت
local var local out; out=$(cmd)متغیر محلی؛ بدون پنهان‌کردن کد خروج
log() { echo "$(date +%T) $*" | tee -a "$LOG"; }چاپ و ثبت در فایل
die() { echo "Error: $*" >&2; exit 1; }خطا و خروج
source "$script_dir/lib.sh"آوردن کتابخانه‌ی توابع
declare -f name type -a nameدیدن تعریف / همه‌ی معنی‌های یک اسم
unset -f name command nameحذف تابع / رد کردن تابع
export -f nameرساندن تابع به bash فرزند

آرایه‌ها

دستورکاری که می‌کند
arr=(a b "c d") arr+=(e)ساخت / افزودن
"${arr[@]}" ${arr[0]} ${arr[-1]}همه (جدا جدا) / یک عضو / آخرین
${#arr[@]} "${!arr[@]}"تعداد / اندیس‌ها
for x in "${arr[@]}"; do ...; doneپیمایش مقدارها
for i in "${!arr[@]}"; do ...; doneپیمایش با اندیس
unset 'arr[1]' arr=("${arr[@]}")حذف (سوراخ) / فشرده‌سازی مجدد
files=(*.txt)آرایه از فایل‌ها (امن برای فاصله)
mapfile -t lines < fileهر خط فایل یک عضو
IFS=, read -ra parts <<< "a,b,c"شکستن رشته به آرایه
declare -A map; map[k]=vآرایه‌ی انجمنی
"${!map[@]}" [[ -v map[k] ]] ((map[$k]++))کلیدها / وجود کلید / شمارش
declare -p arrدیدن ساختار دقیق آرایه

کار با رشته‌ها

دستورکاری که می‌کند
${#s} ${s:2:3} ${s: -3}طول / برش / سه کاراکتر آخر
${p##*/} ${p%/*}اسم فایل / پوشه (basename و dirname)
${f##*.} ${f%.*} ${f%%.*}پسوند / بی‌آخرین‌پسوند / بی‌همه‌ی‌پسوندها
${f%.txt}.mdتغییر پسوند
${s#pat} ${s##pat} ${s%pat} ${s%%pat}حذف پیشوند/پسوند (کوتاه و بلند)
${s/old/new} ${s//old/new}جایگزینی اولی / همه
${s//[^a-z0-9]/}حذف هر چیز جز حرف و عدد
${s^^} ${s,,} ${s^}بزرگ / کوچک / حرف اول بزرگ (Bash 4+)
${v:-d} ${v:=d} ${v:+alt}پیش‌فرض / پیش‌فرض و ذخیره / فقط اگر مقدار دارد
${v:?پیام}اگر خالی بود، پیام و توقف
"${files[@]%.txt}"حذف پسوند از همه‌ی عضوهای آرایه
${!name} ${s@Q}گسترش غیرمستقیم / رشته‌ی امن برای استفاده‌ی مجدد

here-doc و پردازش متن در اسکریپت

دستورکاری که می‌کند
cat <<EOF > file ... EOFنوشتن متن چندخطی با گسترش متغیر
cat <<'EOF'متن خام (بدون گسترش)
cat <<-EOFتورفتگی با tab مجاز
cat >> file <<EOFافزودن به انتهای فایل
sudo tee file > /dev/null <<EOFنوشتن در فایل نیازمند root
var=$(cat <<EOF ... EOF)ریختن متن چندخطی در متغیر
grep -c pat f grep -q pat f grep -F "$x" fشمارش / فقط کد خروج / متن دقیق
grep -oE "[0-9.]+" f | sort | uniq -c | sort -rnشمردن و رتبه‌بندی
sed "s|__KEY__|$value|g" tplپرکردن قالب (جداکننده‌ی |)
sed -i.bak "s/old/new/" fویرایش درجا (GNU و macOS)
awk '$9 >= 400 {print $1}' fشرط روی ستون
awk -v min="$x" '$10 > min' f awk '{c[$9]++} END {...}'متغیر شل با -v / شمارش با آرایه

اسکریپت حرفه‌ای

مدیریت خطا

دستورکاری که می‌کند
set -euo pipefailتوقف در خطا، متغیر تعریف‌نشده خطا، شکست وسط pipe
set -Eeuo pipefailهمان، به‌علاوه‌ی اجرای trap ERR داخل تابع‌ها
shopt -s inherit_errexitاثر set -e داخل $(...)
trap cleanup EXITپاک‌سازی در هر نوع خروج
trap 'echo "line $LINENO: $BASH_COMMAND"' ERRگزارش خط و دستور شکست‌خورده
tmp="$(mktemp -d)"پوشه‌ی موقت امن و یکتا
exit 2 die() { echo "$*" >&2; exit 1; }پایان با کد خروج معنادار
cmd || true if ! cmd; thenشکست قابل‌انتظار، بدون توقف
echo "${PIPESTATUS[@]}"کد خروج همه‌ی عضوهای آخرین pipe
${var:-}متغیر اختیاری با set -u
trap -p trap - EXITدیدن و برداشتن trap‌ها
echo $- set -oگزینه‌های فعلی شل

گزینه‌های خط فرمان با getopts

دستورکاری که می‌کند
while getopts ":hvo:" opt; do case $opt in ... esac; doneحلقه‌ی استاندارد خواندن گزینه‌ها
o) output=$OPTARG ;;مقدار گزینه‌ی دارای :
\?) echo "unknown -$OPTARG" >&2; exit 2 ;;گزینه‌ی ناشناخته (حالت بی‌صدا)
:) echo "-$OPTARG needs a value" >&2; exit 2 ;;مقدار جاافتاده (حالت بی‌صدا)
shift $((OPTIND - 1))کنار گذاشتن گزینه‌ها؛ عملوندها در "$@"
./script.sh -v -- -fileپایان گزینه‌ها
usage() { cat <<EOF ... EOF; }پیام راهنما
[[ $n =~ ^[0-9]+$ ]] || die_usage "..."اعتبارسنجی عدد
while (( $# > 0 )); do case $1 in --help) ...;; esac; shift; doneگزینه‌های بلند با حلقه‌ی دستی
--output=*) output=${1#*=} ;;گزینه‌ی بلند با =
local OPTIND=1getopts داخل تابع

دیباگ و کیفیت کد

دستورکاری که می‌کند
bash -n script.shبررسی نحو بدون اجرا
bash -x script.shاجرا با trace کامل
set -x ... set +xtrace فقط یک بخش
PS4='+ ${BASH_SOURCE##*/}:${LINENO}: 'فایل و شماره‌ی خط در trace
exec 7>trace.log; BASH_XTRACEFD=7trace در فایل جدا
declare -p varنوع و مقدار دقیق متغیر
echo "DEBUG: $x" >&2پیام دیباگ روی stderr
shellcheck script.shتحلیل ایستا
shellcheck -f diff s.sh > fix.diff; patch -p1 < fix.diffاعمال اصلاح‌های خودکار
# shellcheck disable=SC2086ساکت کردن آگاهانه‌ی یک هشدار
shfmt -i 4 -d s.sh shfmt -i 4 -w s.shدیدن و اعمال قالب‌بندی

پروژه: بکاپ خودکار و بررسی سلامت سرور

دستورکاری که می‌کند
find "$dest" -maxdepth 1 -name "$base-*.tar.gz" -mtime +7 -print -deleteچرخش امن بکاپ‌های قدیمی
tar -czf "$tmp/$a" -C "$(dirname "$src")" "$(basename "$src")"آرشیو با مسیر نسبی
tar -tzf archive.tar.gz > /dev/nullبررسی سالم‌بودن آرشیو
tmp=$(mktemp -d -p "$dest" .tmp.XXXXXX)پوشه‌ی موقت کنار مقصد
exec 9> /run/lock/x.lock; flock -n 9 || exit 75یک نسخه در هر لحظه
logger -t lx-backup -p user.err -- "msg"نوشتن در syslog
install -m 755 tool /usr/local/bin/نصب ابزار
crontab -e crontab -l crontab -l | sed ... | crontab -ویرایش، دیدن و جایگزینی crontab
30 2 * * * /usr/local/bin/lx-backup /srv/shopهر شب ۲:۳۰
*/5 * * * * /usr/local/bin/lx-health -qهر ۵ دقیقه، فقط موقع مشکل خروجی
grep CRON /var/log/syslogآیا cron کار را اجرا کرد؟
df -P / systemctl is-active nginxدیسک و وضعیت سرویس