فصل 36- گوناگون

‎36.2‎-‏ Wrapperهای پوسته

یک wrapper، اسکریپت پوسته‌ای است که یک فرمان سیستم یا برنامه سودمند را در خود جای می‌دهد تا یک مجموعه پارامتر را پذیرفته و به آن فرمان عبور بدهد. ‎[1]‎ Wrapping (بسته‌بندی) یک اسکریپت در اطراف یک فرمان پیچیده فراخوانی آن را آسانتر می‌کند. این کار مخصوصاً با sed و awk سودمند است.

یک اسکریپت sed یا awk به طور عادی به وسیله یک ‎sed -e 'commands'‎ یا ‎awk 'commands'‎ از خط فرمان فراخوانی می‌گردد. جای دادن چنین اسکریپتی در یک اسکریپت ‎Bash‎ فراخوانی آسانتر آن را میسر کرده، و آن را قابل استفاده مجدد می‌کند. این کار ترکیب کردن امکانات sed و awk، برای مثال لوله‌کشی خروجی مجموعه‌ای از فرمان‌های sed به awk، را نیز مقدور می‌سازد. سپس می‌توانید مانند یک فایل ذخیره شده قابل اجرا، بدون دردسر تایپ مجدد در خط فرمان ، همان شکل اولیه‌ یا ویرایش شده آن را، به طور مکرر فراخوانی کنید.

مثال ‎36-1‎. ‏wrapper پوسته

#!/bin/bash

#   این اسکریپت ساده سطرهای خالی را از یک فایل حذف می‌کند.
#                            فاقد بازبینی وجود شناسه است.
#
#    شاید مایل باشید انجام چنین کاری را به آن اضافه کنید:
#
# E_NOARGS=85
# if [ -z "$1" ]
# then
#  echo "Usage: `basename $0` target-file"
#  exit $E_NOARGS
# fi



sed -e /^$/d "$1"
#     مشابه با ‎sed -e '/^$/d' filename‎ فراخوانی شده از خط فرمان.

# ‎-e‎ یعنی یک فرمان «editing» در ادامه می‌آید (اینجا اختیاری است).
#            ‎^‎ بیانگر ابتدای سطر، و ‎$‎ نشان دهنده انتهای سطر است.
#  این الگو با سطرهایی منطبق است که بین ابتدا و انتهای آنها چیزی
#+                                 وجود ندارد، یعنی سطرهای خالی.
#                                            ‎d‎ فرمان delete است.

# نقل‌قول کردن شناسه خط فرمان، وجود فضای سفید و کاراکترهای خاص در
#+                                  نام فایل را امکان‌پذیر می‌کند.

#   توجه نمایید که این اسکریپت واقعاً فایل مقصد را تغییر نمی‌دهد.
# اگر نیاز به انجام این کار دارید، خروجی آن را تغییر مسیر بدهید.

exit

مثال ‎36-2‎. یک wrapper پوسته اندکی پیچیده‌تر

#!/bin/bash

# subst.sh:     اسکریپتی که الگویی را جایگزین الگوی دیگری در
#+ یک فایل می‌کند، یعنی «‎sh subst.sh Smith Jones letter.txt‎»
#    در فایل ‎letter.txt‎ کلمه Jones را با Smith تعویض می‌کند.

ARGS=3         # اسکریپت سه شناسه لازم دارد.
E_BADARGS=85   #  تعداد شناسه‌ها اشتباه است.

if [ $# -ne "$ARGS" ]
then
  echo "Usage: `basename $0` old-pattern new-pattern filename"
  exit $E_BADARGS
fi

old_pattern=$1
new_pattern=$2

if [ -f "$3" ]
then
    file_name=$3
else
    echo "File \"$3\" does not exist."
    exit $E_BADARGS
fi


# ---------------------------------------------------
#        اینجا جایی است که بخش عمده کار انجام می‌شود.
sed -e "s/$old_pattern/$new_pattern/g" $file_name
# ---------------------------------------------------

#               البته ‎s‎ در sed فرمان جایگزینی است، و
#+              ‎/pattern/‎ آدرس انطباق را نشان می‌دهد.
#   ‎g‎ یا نشانوند سراسری باعث جایگزینی هر مورد انطباق
#+ ‎$old_pattern‎ در هر سطر، نه فقط در سطر اول می‌گردد.
#     برای توضیح دقیق و عمیق، مستندات sed را بخوانید.

exit $?  # برای نوشتن در یک فایل، خروجی این اسکریپت را تغییر مسیر بدهید.

مثال ‎36-3‎. یک wrapper پوسته عمومی که در یک فایل log می‌نویسد

#!/bin/bash
# logging-wrapper.sh
# wrapper پوسته عمومی که عملیاتی را انجام می‌دهد و
#+               آن را در فایل ثبت رخداد می‌نویسد.

DEFAULT_LOGFILE=logfile.txt

#                     دو متغیر زیر را تنظیم کنید.
OPERATION=
#         می‌تواند زنجیر پیچیده‌ای از فرمانها باشد،
#+      برای مثال یک اسکریپت awk یا یک لوله . . .

LOGFILE=
if [ -z "$LOGFILE" ]
then          # اگر تنظیم نیست، پیش‌فرض شود به ...
  LOGFILE="$DEFAULT_LOGFILE"
fi

#  شناسه های خط فرمان برای عملیات، در صورت حضور.
OPTIONS="$@"


#       واقعه‌نگاری آن.
echo "`date` + `whoami` + $OPERATION "$@"" >> $LOGFILE
# اکنون، انجام عملیات.
exec $OPERATION "$@"

# انجام واقعه‌نگاری قبل از عملیات ضروری است. چرا؟

مثال ‎36-4‎. یک wrapper پوسته پیرامون یک اسکریپت awk

#!/bin/bash

#  pr-ascii.sh:          جدولی از کاراکترهای اسکی چاپ می‌کند.

START=33   #       محدوده کاراکترهای اسکی قابل چاپ (دسیمال).
END=127    # برای کاراکترهای غیرقابل چاپ ‎(> 127)‎ کار نمی‌کند.

echo " Decimal   Hex     Character"           #     سرآیند.
echo " -------   ---     ---------"

for ((i=START; i<=END; i++))
do
  echo $i | awk '{printf("  %3d       %2x         %c\n", $1, $1, $1)}'
#   فرمان داخلی printf خود Bash در این مضمون کار نخواهد کرد:
#  printf "%c" "$i"
done

exit 0


#  Decimal   Hex     Character
#  -------   ---     ---------
#    33       21         !
#    34       22         "
#    35       23         #
#    36       24         $
#
#    . . .
#
#   122       7a         z
#   123       7b         {
#   124       7c         |
#   125       7d         }


# خروجی این اسکریپت را به یک فایل تغییر مسیر بدهید
#+     یا به صورت ‎sh pr-asc.sh | more‎ لوله‌کشی کنید

مثال ‎36-5‎. یک wrapper پوسته پیرامون یک اسکریپت awk دیگر

#!/bin/bash

#              یک ستون مشخص شده (از اعداد) در یک فایل هدف را جمع می‌زند.
# اعداد اعشاری (دسیمال) نیز قبول است، زیرا awk می‌تواند با آنها کار کند.

ARGS=2
E_WRONGARGS=85

if [ $# -ne "$ARGS" ] # بازبینی برای صحیح بودن تعداد شناسه‌های خط فرمان.
then
   echo "Usage: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

#  عبور دادن متغیرهای پوسته به بخش awk اسکریپت یک مقدار ماهرانه است.
# یک روش، نقل‌قولِ پر قدرتِ متغیرِ اسکریپت Bash در داخل اسکریپت awk است.
#    $'$BASH_SCRIPT_VAR'
#     ^                ^
# این کار در اسکریپت awk جاسازی شده زیر انجام می‌شود.
#          برای جزییات بیشتر، مستندات awk را ببینید.

#  در اینجا اسکریپت چند سطری awk چنین فراخوانی می‌شود
#   awk '
#   ...
#   ...
#   ...
#   '


#  شروع اسکریپت awk
# -----------------------------
awk '

{ total += $'"${column_number}"'
}
END {
     print total
}     

' "$filename"
# -----------------------------
# پایان اسکریپت awk


# ممکن است عبور دادن متغیرهای پوسته به یک اسکریپت تعبیه شده awk بی‌خطر
#+  نباشد، بنابراین ‎Stephane Chazelas‎ جایگزین پایین را پیشنهاد می‌کند:
#   ---------------------------------------
#   awk -v column_number="$column_number" '
#   { total += $column_number
#   }
#   END {
#       print total
#   }' "$filename"
#   ---------------------------------------


exit 0

برای اسکریپت‌هایی که نیازمند یک ابزار منفرد همه کاره، یک چاقوی نظامی سوییسی هستند، Perl وجود دارد. Perl توانایی‌های sed و awk را ترکیب می‌کند و برای مفید بودن، زیر مجموعه بزرگی از C هم اضافه می‌کند. پیمانه‌ای و شامل پشتیبانی برای هر محدوده‌ای، از برنامه‌نویسی شیی‌گرا تا من جمله سینک آشپزخانه، است. اسکریپت‌های کوتاه Perl برای جاسازی در اسکریپت‌های پوسته مناسب هستند، و شاید این ادعا که پرل می‌تواند به طور کلی جانشین اسکریپت‌نویسی پوسته شود، اندکی معنا و مفهوم داشته باشد (با این وجود، نویسنده راهنمای ABS با شک‌ و تردید به آن می‌نگرد).

مثال ‎36-6‎. پرل تعبیه شده در یک اسکریپت Bash

#!/bin/bash

# فرمان‌های پوسته می‌توانند مقدم بر اسکریپت پرل باشند.
echo "This precedes the embedded Perl script within \"$0\"."
echo "==============================================================="

perl -e 'print "This line prints from an embedded Perl script.\n";'
#      مانند sed، پرل نیز از گزینه ‎-e‎ استفاده می‌کند.

echo "==============================================================="
echo "However, the script may also contain shell and system commands."

exit 0

حتی ترکیب کردن یک اسکریپت Bash و اسکریپت Perl در داخل یک فایل نیز امکان‌پذیر است. نسبت به اینکه اسکریپت چگونه فراخوانی بشود، یا بخش Bash یا بخش Perl اجرا خواهد گردید.

مثال ‎36-7‎. اسکریپ‌های ترکیب شده Bash و Perl

#!/bin/bash
# bashandperl.sh

echo "Greetings from the Bash part of the script, $0."
#  اینجا فرمان‌های Bash بیشتری می‌تواند ادامه یابد.

exit
#                         پایان بخش Bash اسکریپت.

# ===============================================

#!/usr/bin/perl
# این بخش اسکریپت باید به این طریق فراخوانی گردد:
#  perl -x bashandperl.sh

print "Greetings from the Perl part of the script, $0.\n";
#  به نظر نمی‌رسد پرل به echo تمایل داشته باشد ...
#  اینجا فرمان‌های Perl بیشتری می‌تواند ادامه یابد.

#                         پایان بخش Perl اسکریپت.

bash$ bash bashandperl.sh
Greetings from the Bash part of the script.

bash$ perl -x bashandperl.sh
Greetings from the Perl part of the script.

البته، حتی جای دادن زبان‌های اسکریپت‌نویسی خارجی دیگر نیز در درون wrapperهای پوسته امکان‌پذیر است. برای مثال Python ...

مثال ‎36-8‎. پایتون جاسازی شده در یک اسکریپت Bash

#!/bin/bash
# ex56py.sh

# فرمان‌های پوسته می‌توانند جلوتر از اسکریپت پایتون قرار داشته باشند.
echo "This precedes the embedded Python script within \"$0.\""
echo "==============================================================="

python -c 'print "This line prints from an embedded Python script.\n";'
# بر خلاف sed و perl، پایتون گزینه ‎-c‎ را به کار می‌برد.
python -c 'k = raw_input( "Hit a key to exit to outer script. " )'

echo "==============================================================="
echo "However, the script may also contain shell and system commands."

exit 0

با بسته‌بندی یک اسکریپت اطراف mplayer و سرویس‌دهنده ترجمه گوگل، می‌توانید چیزی تولید کنید که به شما جواب بدهد.

مثال ‎36-9‎. اسکریپتی که صحبت می‌کند

#!/bin/bash
#                                  با احترام برگرفته از:
# http://elinux.org/RPi_Text_to_Speech_(Speech_Synthesis)

# برای اینکه اسکریپت کار کند، شما باید آنلاین باشید، طوری
#+     که بتوانید سرویس‌دهنده ترجمه گوگل را دستیابی کنید.
#   البته، mplayer نیز باید روی کامپیوتر شما موجود باشد.

speak()
  {
  local IFS=+
  #   فراخوانی mplayer، سپس متصل شدن به سرور ترجمه گوگل.
  /usr/bin/mplayer -ao alsa -really-quiet -noconsolecontrols \
 "http://translate.google.com/translate_tts?tl=en&q=$*"
  #          گوگل ترجمه می‌کند، اما صحبت هم می‌تواند بکند.
  }

LINES=4

spk=$(tail -$LINES $0)     # دنباله پایانی همین اسکریپت!
speak "$spk"
exit
# Browns. Nice talking to you.

توضیح مترجم: می‌توانیم ۴ سطر متن به انتهای این اسکریپت اضافه کرده و سپس اسکریپت را اجرا کنیم، که آن چهار سطر توسط سرور گوگل خوانده می‌شود. اگر مایل باشید می‌شود شناسه تابع speak در خود اسکریپت را حذف کرده و سپس اسکریپت را با متن مورد نظر فراخوانی نمود، که در این حالت متن داده شده را می‌خواند.

مثال جالبی از یک wrapper پوسته پیچیده، اسکریپت undvd نوشته ‎Martin Matusiak است، که یک واسط خط فرمان با استفاده آسان برای برنامه سودمند پیچیده mencoder فراهم می‌کند. یک نمونه دیگر Ext3Undel، نوشته ‎Itzchak Rehberg‎ می‌باشد، که یک مجموعه اسکریپت برای بازیابی فایل‌های حذف شده در یک ساختار فایل ext3 است.

یادداشت‌ها

‎[1]‎

در واقع، تعدادی از برنامه‌های مفید لینوکس، wrapperهای پوسته هستند. برخی نمونه‌ها عبارتند از، ‎/usr/bin/pdf2ps‎‏، ‎/usr/bin/batch‎، و ‎/usr/bin/xmkmf‎.