فصل ۲۴ – نوشتن شلاسکریپت
تا اینجا دستورهای شل را به صورت تعاملی اجرا کردهایم؛ هر بار فرمانی را تایپ کردهایم و نتیجه را دیدهایم.
شلاسکریپتها به ما اجازه میدهند مجموعهای از این فرمانها را در یک فایل متنی ذخیره کنیم تا بعداً با یک دستور ساده اجرا شوند.
در این فصل نخستین اسکریپتهای خود را مینویسیم، نحوهٔ اجرا و اشکالزداییشان را یاد میگیریم و با مفاهیمی آشنا میشویم که در فصلهای بعدی گسترش خواهند یافت.
اسکریپت چیست؟
یک اسکریپت در سادهترین حالت فایلی است شامل مجموعهای از دستورات شل که به ترتیب اجرا میشوند.
همان دستوراتی که قبلاً در خط فرمان وارد میکردید، میتوانند داخل اسکریپت قرار گیرند تا بارها و بارها قابل استفاده باشند.
مزیت اصلی اسکریپتها خودکارسازی و تکرارپذیری است: کارهایی را که به صورت دستی انجام میدهید به اسکریپت میسپارید تا هر وقت نیاز بود دوباره اجرا شود.
اولین اسکریپت ما
یک اسکریپت باید فایلی متنی باشد، بنابراین از ویرایشگر دلخواه استفاده میکنیم. مثالهای کتاب از nano بهره میبرند.
فایلی به نام hello_world.sh بسازید و خطوط زیر را در آن قرار دهید:
#!/bin/bash
# hello_world.sh - نمونهای ساده از یک اسکریپت bash
echo "سلام دنیا!"
خط اول شبانگ (#!) است که به سیستم میگوید این فایل باید با /bin/bash اجرا شود.
خط دوم یک نظر است و نادیده گرفته میشود. خط سوم دستور آشنای echo است.
فایل را ذخیره کنید و سپس اجازهٔ اجرا بدهید:
[me@linuxbox ~]$ chmod 755 hello_world.sh
مجوز 755 یعنی صاحب فایل حق خواندن، نوشتن و اجرا دارد و سایر کاربران فقط میتوانند فایل را بخوانند و اجرا کنند.
اکنون میتوانیم آن را اجرا کنیم:
[me@linuxbox ~]$ ./hello_world.sh
سلام دنیا!
اگر فایل در دایرکتوری فعلی نباشد یا مجوز اجرا نداشته باشد، میتوانیم آن را مستقیماً به bash بدهیم:
[me@linuxbox ~]$ bash hello_world.sh
آشنایی بیشتر با شبانگ
شبانگ در ابتدای فایل تعیین میکند که چه برنامهای اسکریپت را تفسیر کند. چند نمونهٔ رایج:
#!/bin/sh # شل استاندارد سیستم (ممکن است dash یا bash باشد)
#!/usr/bin/env python3 # اجرای اسکریپت Python با جستوجو در PATH
#!/usr/bin/perl # اجرای اسکریپت Perl
اگر شبانگ حذف شود و اسکریپت را با نامش اجرا کنیم، هسته تلاش میکند آن را به عنوان یک برنامهٔ دودویی بارگذاری کند و شکست میخورد.
اما اگر اسکریپت را به صراحت به bash بدهیم (bash script.sh)، شل آن را بدون شبانگ هم اجرا خواهد کرد.
محل نگهداری اسکریپتها
برای اینکه اسکریپتها از هر جایی قابل فراخوانی باشند، باید در مسیری قرار گیرند که در متغیر محیطی PATH فهرست شده است.
بسیاری از کاربران دایرکتوری ~/bin را برای این منظور ایجاد میکنند:
[me@linuxbox ~]$ mkdir -p ~/bin
[me@linuxbox ~]$ mv hello_world.sh ~/bin/hello
سپس اطمینان حاصل کنید که مسیر تازه به PATH اضافه شده است. اگر در خروجی دستور زیر مسیر ~/bin را نمیبینید، آن را به ~/.bashrc اضافه کنید:
export PATH="$HOME/bin:$PATH"
پس از باز کردن شل جدید (یا اجرای source ~/.bashrc) میتوانید تنها با تایپ hello اسکریپت را اجرا کنید.
گفتنی است که وجود پسوند .sh الزامی نیست؛ بسیاری از کاربران نام کوتاهتری بدون پسوند برای اسکریپتهای اجرایی خود انتخاب میکنند.
ایجاد فایل با cat
گاهی لازم است اسکریپتی را به سرعت ایجاد کنیم. میتوانیم از دستور cat و یک here document بهره ببریم:
[me@linuxbox ~]$ cat <<'EOF' > ~/bin/cleanup
#!/bin/bash
rm -i *.bak *.tmp
EOF
[me@linuxbox ~]$ chmod 755 ~/bin/cleanup
علامت 'EOF' تعیین میکند که محتوای بین دو نشانه بدون جایگزینی متغیرها نوشته شود.
این ترفند در طول فصلهای بعدی نیز به کار میآید.
پروژهٔ نمونه: ساخت صفحهٔ گزارش سیستم
برای تمرین، اسکریپتی مینویسیم که گزارشی HTML از وضعیت سیستم تولید کند. نام فایل را sys_info_page میگذاریم و آن را در ~/bin ذخیره میکنیم.
هدف اسکریپت تولید فایل /tmp/system_info.html با محتوای پویا است.
ابتدا چارچوب کلی را مینویسیم:
#!/bin/bash
# sys_info_page - تولید یک صفحهٔ HTML ساده شامل اطلاعات سیستم
TITLE="گزارش وضعیت سیستم برای \$HOSTNAME"
CURRENT_TIME=$(date +"%x %r %Z")
TIME_STAMP="گزارش تولید شده در $CURRENT_TIME توسط $USER"
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIME_STAMP</p>
</body>
</html>
_EOF_
نکتههای مهم:
- از جایگزینی فرمان (
$(...)) برای ذخیرهٔ خروجیdateدر متغیرCURRENT_TIMEاستفاده کردهایم. - متغیرها (
$HOSTNAME,$USER) هنگام اجرای here document جایگزین میشوند. - نام
_EOF_صرفاً یک نشانه است؛ میتواند هر واژهٔ دیگری باشد، فقط باید با همان نام پایان یابد.
اسکریپت بالا صفحهای ساده میسازد. اکنون بخش بدنه را گسترش میدهیم تا اطلاعات بیشتری نمایش دهد:
cat << _EOF_
<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIME_STAMP</p>
<h2>اطلاعات سیستم</h2>
<pre>$(uname -mp)</pre>
<h2>زمان راهاندازی</h2>
<pre>$(uptime)</pre>
<h2>کاربران فعال</h2>
<pre>$(who)</pre>
<h2>فضای دیسک</h2>
<pre>$(df -h)</pre>
</body>
</html>
_EOF_
با اجرای اسکریپت صفحهای با فرمت HTML در /tmp/system_info.html ساخته میشود. میتوانید آن را با مرورگر باز کنید.
بهبود خروجی
میتوانیم خروجی اسکریپت را مستقیماً در فایل ذخیره کنیم و در صورت موفقیت پیام مناسبی نمایش دهیم:
FILE=/tmp/system_info.html
if cat << _EOF_ > $FILE
<html>
<head>
<title>$TITLE</title>
</head>
<body>
<h1>$TITLE</h1>
<p>$TIME_STAMP</p>
<h2>اطلاعات سیستم</h2>
<pre>$(uname -mp)</pre>
<h2>زمان راهاندازی</h2>
<pre>$(uptime)</pre>
<h2>کاربران فعال</h2>
<pre>$(who)</pre>
<h2>فضای دیسک</h2>
<pre>$(df -h)</pre>
</body>
</html>
_EOF_
then
echo "گزارش در $FILE ذخیره شد"
else
echo "ایجاد فایل با خطا روبهرو شد" >&2
exit 1
fi
دستور cat << _EOF_ > $FILE در صورت موفقیت مقدار بازگشتی صفر دارد؛ بنابراین میتوانیم از آن در دستور if استفاده کنیم.
قالببندی و خوانایی
- برای بخشهای منطقی توضیح کوتاهی با
#بنویسید. - دستورات را با فاصلهٔ مناسب بچینید تا خواندن آسان شود.
- از نام متغیرهای معنادار (
TITLE,FILE) استفاده کنید.
اشکالزدایی و آزمون
دو ابزار ساده در bash برای بررسی اسکریپت وجود دارد:
bash -n script.sh– تنها نحو (syntax) را بررسی میکند و اسکریپت را اجرا نمیکند.bash -x script.sh– هر فرمان را قبل از اجرا چاپ میکند؛ برای دنبال کردن جریان اجرای برنامه مفید است.
همچنین میتوانید درون اسکریپت از set -x برای فعال کردن حالت ردگیری و set +x برای غیرفعال کردن آن در بخشهای مشخص استفاده کنید.
دسترسی و ایمنسازی
به طور معمول برای اسکریپتهای شخصی از مجوز 755 استفاده میشود تا صاحب فایل حق نوشتن داشته باشد و سایرین فقط بخوانند و اجرا کنند.
اگر اسکریپتی اطلاعات حساسی در بر دارد، مجوز را محدودتر کنید یا آن را خارج از مسیر PATH عمومی نگه دارید.
انتقال و به اشتراکگذاری اسکریپت
اسکریپتها فایلهای متنی هستند. میتوانید آنها را به راحتی با دوستانتان به اشتراک بگذارید، در مخازن Git قرار دهید یا در وب منتشر کنید.
در صورت استفاده در توزیعهای مختلف، از ساختار قابلحمل (POSIX sh) بهره ببرید یا در مستندات بنویسید که اسکریپت مخصوص bash است.
جمعبندی
- یک شلاسکریپت مجموعهای از دستورات bash است که در فایل متنی ذخیره میشود.
- با افزودن خط شبانگ و مجوز اجرا میتوانیم آن را مانند هر برنامهٔ دیگری اجرا کنیم.
- استفاده از here document، جایگزینی فرمان و متغیرها به ما امکان میدهد خروجیهای پیچیدهتری تولید کنیم.
- ابزارهایی مانند
bash -nوbash -xدر اشکالزدایی کمک میکنند.
تمرینها
- اسکریپت
sys_info_pageرا گسترش دهید تا خروجیip addr showرا در بخشی جداگانه نمایش دهد. - اسکریپتی بنویسید که از دایرکتوری مشخصی نسخهٔ پشتیبان میگیرد: ابتدا فهرست فایلها را با
tarآرشیو و سپس باgzipفشرده کند. نام فایل شامل تاریخ روز باشد. - با استفاده از
bash -xاسکریپتهای خود را اجرا کنید و یادداشت کنید هر فرمان قبل از اجرا چگونه در خروجی نشان داده میشود.
مطالعهٔ بیشتر
- صفحهٔ راهنمای
man bash، به ویژه بخش «INVOCATION» دربارهٔ خط شبانگ و گزینههای پوسته. - کتاب «Advanced Bash-Scripting Guide» برای مثالهای پیچیدهتر.
- مستندات ابزار
shellcheckکه میتواند خطاهای رایج در اسکریپتها را تشخیص دهد.