برنامه‌نویسی

آموزش Bash Scripting


۲۶ اسفند ۱۳۹۹
آموزش bash scripting

در این مقاله شما را با اسکریپت‌نویسی و چگونگی شروع کار با آن آشنا خواهیم کرد بنابراین فرض را براین می‌گیریم که با دستورهای Shell و Linux آشنا هستید.

Shell Script چیست؟

Shell Script یک برنامه متنی ساده مبتنی بر Command line است که دستورهایی را به‌ترتیب توسط مفسر Bash اجرا می‌کند. اکثرا از Shell Script برای خودکارسازی فرایندهای روزمره مانند پشتیان‌گیری از فایل‌ها، نصب پکیج‌های مورد نیاز روی سرورهای مختلف، عیب‌یابی و … استفاده می‌کنند زیرا به صرفه‌جویی در وقت و افزایش بهره‌وری توسعه‌دهنده و مسئول DevOps یا حتی کاربران عادی کمک می‌کند.

اگر برای انجام یک کار مرتبا دستورهای ساده یا حتی پیچیده را پشت سر هم اجرا می‌کنید بنابراین یادگیری نوشتن Shell Script می‌تواند برای شما مفید باشد. نام‌گذاری Shell Script بر عهده‌ی شما است و می‌توانید از نام‌های دلخواه خودتان استفاده کنید اما بایستی به مجوز‌های مورد نیاز برای اجرای آن اسکریپت نیز توجه داشته باشید. توصیه‌ ما این است که از نام‌های توصیفی استفاده کنید.

از پسوند .sh در نام‌گذاری اسکریپت‌ها استفاده می‌شود زیرا مشخص می‌کند که این فایل یک اسکریپت است اما در سیستم‌عامل Linux می‌توانید اسکریپت‌ها را بدون نیاز به استفاده از این پسوند، اجرا کنید.

ساختار یک Shell Script

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

#!/bin/bash

بعد از مشخص کردن مفسر می‌توانید توضیح‌های مورد نیاز، نام توسعه‌دهنده و دیگر موارد اینچنینی را قرار دهید. هر چیزی که پس از یک # قرار بگیرد به‌عنوان یک کامنت در اسکریپت شناخته شده و مفسر آن را اجرا نمی‌کند:

# Name of Script: test.sh
# A simple bash script to illustrate some basic concepts
# Author: Goodness Chris-Ugari
# Date: 16-02-2021

پس از قرار دادن توضیح‌ها در حالت کامنت می‌توانید مجموعه دستورهایی که می‌خواهید اجرا شوند را در اسکریپت تعریف کنید:

#!/bin/bash
# Name of Script: test.sh
# A simple bash script to illustrate some basic concepts
# Author: Goodness Chris-Ugari
# Date: 16-02-2021

# Display Hello, World
echo Hello, world

# Display the present/current working directory
pwd

کدهای فوق را در یک فایل با نام test.sh ذخیره کرده و با اجرای دستور ./test.sh در مسیر این اسکریپت می‌توانید خروجی آن را مشاهده کنید:

اجرای shell script

استفاده از متغیرها

استفاده از متغیرها در زمانی که می‌خواهید داده‌هایی را موقتا ذخیره کنید بسیار مفید است. توجه داشته باشید که Bash به حروف کوچک و بزرگ حساس است بنابراین در تعریف و استفاده از متغیرها دقت داشته باشید. پس از تعریف متغیر می‌توانید مقدار آن را با استفاده از $ فراخوانی کنید:

# Declare a variable NAME and assign a value to it.
MOOD=Excited!

# Display "I am Excited!"
echo I am $MOOD

مطمئنا می‌توانید خروجی اسکریپت فوق را حدس بزنید. برای رشته‌های (strings) پیچیده‌تر بایستی از double quotationها استفاده کنید. برای مثال:

# Declare a variable NAME and assign a value to it.
MOOD="very excited"

# Display "I am very excited"
echo I am $MOOD

جایگزینی دستورها

شما می‌توانید خروجی یک دستور را در یک متغیر ذخیره کنید و این کار باعنوان Command Substitution شناخته می‌شود. برای پیاده‌سازی Command Substitution بایستی از $ قبل از پرانتزهای دربرگیرنده‌ی دستور مورد نظر استفاده کنید:

#The code below will return the number of entries in a directory.
dirContents=$(ls | wc -l)
echo The number of entries in this directory is $dirContents

متغیرهای خاص

متغیرهای خاص متغیرهایی هستند که به‌طور خودکار برای شما تنظیم می‌شوند. در اینجا برخی از آن‌ها ذکر شده است:

  • $0: نام اسکریپت در این متغیر ذخیره می‌شود.
  • $n: پارامترهای ورودی اسکریپت در این متغیر به‌صورت $1 یعنی پارامتر اول یا $2 یعنی پارامتر دوم، ذخیره می‌شود.
  • $#: این متغیر تعداد پارامترهای ورودی را نشان می‌دهد.
  • $*: تمام پارامترهای ورودی در این متغیر ذخیره می‌شوند.
  • $?: وضعیت خروجی آخرین دستور اجرا شده نمایش داده می‌شود. 0 به‌معنای موفقیت آمیز بودن اجرا دستور و 1 به‌معنی اجرا نشدن دستور است.
  • $$: شناسه فرایند فعلی اسکریپت در این متغیر ذخیره می‌شود.

اپراتورهای اصلی

در Bash می‌توانید به اپراتورهایی که در ادامه بررسی می‌کنیم دسترسی داشته باشید:

اپراتورهای محاسباتی

اپراتورتوضیحاتنحوه‌ی استفاده
+جمعnum1 + num2
تفریقnum1 – num2
*ضربnum1 * num2
/تقسیمnum1 / num2
%مدولnum1 % num2
=مقداردهی$num = value

می‌توانید از اپراتورهای محاسباتی به‌چندین روش مانند استفاده از کلیدواژه‌های let یا expr، پرانتز یا براکت به‌همراه $ استفاده کنید. همچنین توجه داشته باشید که نمی‌توانید مستقیما از اپراتورهای محاسباتی استفاده کنید:

#!/bin/bash

#
let myVariable=2+3 #If you are declaring the expression without quotes, then you must ensure that the expression doesn't contain spaces.
echo $myVariable #This will output 5

#Using the let command
let "myVariable = 2 + 3" #You can have spaces within quotes.
echo $myVariable # This will output 5

let myVariable++ #Will increment the last value of $myVariable, so $myVariable will now be 6

#Using the expr command
expr 2 + 3 #You must include space when using the expr command and do not enclose the expression in quotes. This line will output the addition of the two numbers.

expr "2 + 3" #Will be treated as a string and will output 2 + 3
expr 2+3 #Will be treated as a string and will output 2+3

#Using brackets
echo $[2+3] #Will work with or without spaces and output the addition of the numbers.
echo $((2+3)) #Will also work with or without spaces.

توجه داشته باشید که کلید واژه‌ی let به شما کمک می‌کند تا خروجی محاسبات را در یک متغیر ذخیره کنید اما expr فقط نتیجه را در خروجی نمایش می‌دهد.

اپراتورهای رابطه‌ای

اپراتورتوضیحاتنحوه‌ی استفاده
-eqبرابر است با$num1 -eq $num2
-neبرابر نیست با$num1 -ne $num2
-gtبزرگ‌تر از$num1 -gt $num2
-ltکوچک‌تر از$num1 -lt $num2
-geبزرگ‌تر یا مساوی است با$num1 -ge $num2
-leکوچک‌تر یا مساوری است با$num1 -le $num2

توجه داشته باشید که اپراتورهای رابطه‌ای را نمی‌توانید برای stringها استفاده کنید.

Boolean

اپراتورتوضیحاتنحوه‌ی استفاده
!نفی!
-oیاconditon1 -or condition2
-a (&&)وcondition1 -a condition2

علاوه‌براین‌ها می‌توانید از || به‌عنوان OR و از && به‌عنوان AND استفاده کنید.

اپراتورهای مرتبط با String

اپراتورتوضیحاتنحوه‌ی استفاده
=برابر است با، نتیجه به‌صورت مقادیر بولی برگشت داده می‌شود$string1=string2
!=برابر نیست با، نتیجه به‌صورت مقادیر بولی برگشت داده می‌شود$string1!=$string2
-zتعداد کاراکترهای یک رشته را بررسی می‌کند. اگر تعداد کاراکترهای برابر با صفر بود، مقدار صحیح برگشت داده می‌شود-z $string
-nبررسی می‌شود که کاراکترهای یک رشته برابر با صفر نباشد.-n $string

اپراتورهای مرتبط با فایل

اپراتورتوضیحاتنحوه‌ی استفاده
-dدایرکتوری بودن ورودی را بررسی می‌کند-d $file
-fفایل بودن ورودی را بررسی می‌کند-f $file
-pنامگذاری ورودی بررسی می‌شود-p $file
-rمجوز خواندن فایل بررسی می‌شود-r $file
-wمجوز نوشتن در فایل بررسی می‌شود-w $file
-xقابل اجرا بودن فایل بررسی می‌شود-x $file
-sبررسی می‌شود که اندازه‌ی فایل بیشتر از صفر باشد-s $file
-eموجود بودن فایل بررسی می‌شود-e $file

حلقه‌ها

از حلقه‌ها برای اجرای مکرر یک سری دستورها می‌توان استفاده کرد.

حلقه for

سینتکس حلقه For به شکل زیر است:

for var in <list>
do
    <command>
done

مثال:

#!/bin/bash

#This will print numbers 1 to 5
for value in {1..5}
do
   echo $value
done

حلقه while

از این حلقه در حالی استفاده می‌شود که یک شرط مشخص برابر با true باشد. سینتکس حلقه‌ی While به شکل زیر است:

while [ <condition> ]
do
    <command>
done

مثال:

#Will print numbers 1 to 5
count=1
while [ $count -le 5 ]
do
echo $count
((count++)) #Will increment count by 1 after every loop
done

حلقه until

این حلقه تا زمانی که یک شرط معین برابر با true شود به اجرای دستورهای درون خود ادامه می‌دهد. سینتکس حلقه Until به شکل زیر است:

until [ <condition> ]
do
    <command>
done

مثال:

#Will print numbers 1 to 5
count=1
until [ $count -gt 5 ] #Loop will stop one count is greater than 5
do
echo $count
((count++)) #Will increment count by 1 after every loop
done

فانکشن

فانکشن یک بلوک از کدها است که قابلیت استفاده مجدد دارد بنابراین می‌توان با تعریف آن‌ها از تکرار کدها جلوگیری کنیم و هر زمان که به یک عملکرد خاص نیاز داشتیم فقط از فانکشن آن استفاده کنیم. از سینتکس زیر برای تعریف فانکشن استفاده می‌شود:

#Without the function keyword
function_name () {
       <commands>
}

یا

#With the function keyword
function function_name {
       <commands>
}

مثال:

#!bin/bash
#A function that prints out the first argument supplied to it
 function printArg () {
          echo The first argument is $1
}
#Function call with an argument
printArg "Hello World"

#The output of the function above will be "The first argument is Hello World"

هر دو سینتکس فوق قابل استفاده هستند و نتیجه‌ی یکسانی دارند بنابراین تصمیم استفاده از هرکدام آن‌ها با خود شما است. پرانتزهایی که پس از فانکشن printArg قرار داده شده برخلاف دیگر زبان‌های برنامه‌نویسی که از آن‌ها برای پارامترهای ورودی استفاده می‌شود، Bash به این شکل نیست.

نباید چیزی در این پرانتزها قرار دهید و برای ارسال پارامترهای مختلف به هر فانکشن بایستی مستقیما داده‌های ورودی خود را پس از فانکشن قرار دهید. توجه داشته باشید که قبل از تعریف یک فانکشن‌ نمی‌توانید آن را فراخوانی کنید.

عبارت‌های شرطی در اسکریپت‌های Bash

عبارت‌های شرطی به شما امکان می‌دهند تا عملکردهای خاصی را بر اساس شرایط معین شده‌ای ارائه دهید.

عبارت شرطی if

در عبارت‌ شرطی if اگر شرط تعیین شده‌ی ما برابر با true باشد، عملکردهای مورد نظر ما اجرا می‌شوند در غیر این صورت، این بخش از کد نادیده گرفته شده و بقیه‌ی کدها اجرا می‌شوند. سینتکس تعریف عبارت شرطی if به شکل زیر است:

if [ <condition/test> ]
then
      <command>
fi

عبارت شرطی if else

این عبارت شرطی عملکردی شبیه عبارت شرطی if دارد اما با استفاده از این عبارت شرطی، مفسر پس از برقرار نشدن شرط اولیه، کدهای بلوک دوم این عبارت شرطی را اجرا می‌کند. سینتکس این عبارت شرطی به شکل زیر است:

if [ <condition/test> ]
then
      <command1>
else
      <command2>
fi

مثال:

#!bin/bash
#This script will take 2 numbers as command-line arguments. It will print to the screen the larger of the two numbers.

if [ $1 -gt $2 ]

then
   echo $1
else
   echo $2
fi
خروجی عبارت شرطی if else

عبارت شرطی if elif else

برای تعیین کردن چند شرط مختلف می‌توانیم از عبارت شرطی if elif else استفاده کنیم که سینتکس آن به شکل زیر است:

if [ <condition1> ]
then
      <command1>
elif [ <condition2> ]
then
      <command2>
elif [ <condition3> ]
then
      <command3>
else
      <command>
fi

مثالی که یک پیام ساده را بر اساس روزهای هفته چاپ می‌کند:

#!/bin/bash
#script to print a message based upon which day of the week it is.

day_of_the_week=$(date +%u)

if [ $day_of_the_week -eq 1 ]
then
   echo Today is Monday, aargh!
elif [ $day_of_the_week -eq 2 ]
then
   echo Today is Tuesday
elif [ $day_of_the_week -eq 3 ]
then
   echo Today is Wednesday
elif [ $day_of_the_week -eq 4 ]
then
   echo Today is Thursday
elif [ $day_of_the_week -eq 5 ]
then
   echo Today is Friday, TGIF!
elif [ $day_of_the_week -eq 6 ]
then
   echo Today is Saturday
elif [ $day_of_the_week -eq 7 ]
then
   echo Today is Sunday
else
   echo Something is wrong
fi
خروجی عبارت شرطی if elif else

برای مشاهده‌ی نتایج مختلف می‌توانید زمان سیستم خود را تغییر دهید. همچنین می‌توانید به‌ هرتعداد که می‌خواهید از elif برای تعیین کردن شروط مختلف استفاده کنید، علاوه‌برآن می‌توانید عبارت‌های شرطی if را به‌صورت تودرتو استفاده کنید اما بایستی فاصله‌ها را رعایت کنید.

عبارت شرطی case

درمواردی که عبارت‌های شرطی if و elif باعث ایجاد پیچیدگی می‌شوند می‌تواند از عبارت شرطی case استفاده کنید که سینتکس آن به شکل زیر است:

Case <variable> in
    <pattern1>)
          <command>
          ;;
    <pattern2>)
          <command2>
          ;;
esac

مثال:

#!/bin/bash

echo Which color do you prefer? Blue, Green or Yellow? #This will be printed first when you run the script.
read color #Prompt to accept input

case $color in #Compare using the value entered for color at the prompt********
    Blue)
        echo Feeling blue today?
        ;;
    Green)
        echo The land is green!
        ;;
    Yellow)
        echo It is going to be a sunny day!
        ;;
     *)
        echo Try Again
        ;;
esac #Indicates the end of the case statement
خروجی عبارت شرطی case

منبع: https://goodiec.hashnode.dev/beginners-guide-to-shell-scripting