اسکریپت‌نویسی Bash و خودکارسازی

از دستور تا اسکریپت

وقتی چند دستور را بارها با ترتیب مشخص اجرا می‌کنید، شاید بد نباشد آن‌ها را در یک اسکریپت Bash قرار دهید. اسکریپت باید ورودی روشن، خروجی قابل بررسی و رفتار قابل پیش‌بینی داشته باشد. نخستین خط (Shebang)، مفسر مورد نیاز را مشخص می‌کند:

1#!/usr/bin/env bash
2
3printf 'Hello, %s!\n' "$USER"

فایل را با پسوند .sh ذخیره و به آن مجوز اجرا بدهید:

1chmod u+x report.sh
2./report.sh
3bash report.sh

اجرای ./report.sh به مجوز اجرا نیاز دارد؛ اجرای bash report.sh محتوا را به Bash می‌دهد و به این مجوز نیاز ندارد.

متغیرها، quoteها و آرگومان‌ها

در Bash فاصله اطراف = مجاز نیست. تقریباً همیشه متغیرها را در double quote قرار دهید تا فاصله‌ها و globها باعث شکستن ورودی نشوند:

1name="system report"
2output_dir="${1:-$HOME/reports}"
3printf '%s\n' "$name"
4mkdir -p "$output_dir"
  • $1 نخستین آرگومان اسکریپت است.
  • ${1:-value} اگر آرگومان خالی یا ناموجود باشد، مقدار پیش‌فرض می‌دهد.
  • double quote اجازهٔ بسط متغیر را می‌دهد؛ single quote متن را دقیقاً همان‌طور که نوشته شده نگه می‌دارد.

کد خروج 0 یعنی موفقیت و مقدار غیرصفر یعنی خطا. ورودی را در ابتدای اسکریپت بررسی کنید:

1if (( $# > 1 )); then
2  printf 'Usage: %s [output-directory]\n' "$0" >&2
3  exit 2
4fi

>&2 پیام راهنما را به stderr می‌فرستد تا خروجی عادی اسکریپت قابل استفاده در pipeline بماند.

شرط، حلقه و تابع

این سه ساختار برای بیشتر اسکریپت‌های کوتاه کافی‌اند:

 1is_regular_file() {
 2  [[ -f "$1" ]]
 3}
 4
 5for file in "$@"; do
 6  if is_regular_file "$file"; then
 7    printf 'file: %s\n' "$file"
 8  else
 9    printf 'skipped: %s\n' "$file" >&2
10  fi
11done
  • [[ ... ]] ساختار شرط Bash است و نسبت به [ در اسکریپت Bash رفتار قابل پیش‌بینی‌تری دارد.
  • "$@" آرگومان‌ها را جدا از هم و بدون خراب‌کردن فاصله‌ها نگه می‌دارد.
  • تابع‌ها، تکرار را کم و نام هر بخش از منطق را روشن می‌کنند.

اسکریپت قابل اتکا

برای اسکریپت‌های خودکارسازی، خطا و متغیر تعریف‌نشده را نادیده نگیرید:

 1#!/usr/bin/env bash
 2set -euo pipefail
 3
 4output_dir="${1:-$HOME/system-reports}"
 5timestamp="$(date +%F-%H%M%S)"
 6report="$output_dir/report-$timestamp.txt"
 7
 8mkdir -p "$output_dir"
 9
10{
11  printf 'Generated: %s\n\n' "$(date --iso-8601=seconds)"
12  printf '== Disk usage ==\n'
13  df -h
14  printf '\n== Memory usage ==\n'
15  free -h
16  printf '\n== Failed systemd units ==\n'
17  systemctl --failed --no-legend || true
18} > "$report"
19
20printf 'Report written to %s\n' "$report"
  • -e در نخستین خطای کنترل‌نشده اسکریپت را متوقف می‌کند.
  • -u استفاده از متغیر تعریف‌نشده را خطا می‌داند.
  • pipefail باعث می‌شود شکست دستورهای ابتدای pipeline پنهان نشود.
  • || true در مثال بالا عمدی است: نداشتن unit ناموفق، لاگ را شکست نمی‌دهد.

پیش از استفادهٔ خودکار، اسکریپت را با ورودی عادی، مسیر دارای فاصله و ورودی نامعتبر آزمایش کنید. ShellCheck خطاهای رایج Bash را پیش از اجرا پیدا می‌کند.

زمان‌بندی کارها

برای کارهای شخصی و ساده، cron زمان‌بندی مبتنی بر پنج ستون دارد:

1minute hour day-of-month month day-of-week command

برای ویرایش jobهای کاربر فعلی، crontab -e را اجرا کنید. این نمونه هر روز ساعت ۹ لاگ را می‌سازد:

0 9 * * * /home/ubuntu/bin/system-report  >> /home/ubuntu/system-report.log 2>&1
نمونهٔ فرضی

/home/ubuntu/bin/system-report در این مثال یک اسکریپت فرضی است؛ آن را با مسیر اسکریپت واقعی خودتان جایگزین کنید.

محیط cron محدود است؛ مسیرهای مطلق، متغیرهای محیطی صریح و ثبت خروجی و خطا ضروری‌اند. نام کاربر و مسیر نمونه را با مقدار واقعی سامانهٔ خودتان جایگزین کنید.

برای سرویس‌های سامانه، systemd timer معمولاً انتخاب مناسب‌تری است: وضعیت و لاگ آن با ابزارهای آشنا دیده می‌شود و می‌تواند اجرای ازدست‌رفته هنگام خاموش‌بودن سامانه را جبران کند. این timer روزانه سرویس هم‌نام را اجرا می‌کند:

 1# /etc/systemd/system/system-report.timer
 2[Unit]
 3Description=Run the daily system report
 4
 5[Timer]
 6OnCalendar=*-*-* 09:00:00
 7Persistent=true
 8
 9[Install]
10WantedBy=timers.target

سرویس متناظر باید ExecStart را با مسیر مطلق اسکریپت تعریف کند. پس از ایجاد یا تغییر unitها، پیکربندی را بازبارگذاری و timer را فعال کنید:

1sudo systemctl daemon-reload
2sudo systemctl enable --now system-report.timer
3systemctl list-timers
4journalctl -u system-report.service

خودکارسازی خوب فقط «خودکار اجراشدن» نیست: باید تکرارپذیر، قابل مشاهده و تا حد ممکن idempotent باشد.

منابع یادگیری

مستندات و مقالات

ویدیو