14. نکته‌ها و اشاره‌ها

یونیکس سرشار از برنامه‌های کاربردی کار با متن می‌باشد، برخی ازابزارهای قدرتمندتر را اکنون در این بخش از آموزش بحث خواهیم نمود. اهمیت آن در این است که به طور ضمنی هر چیزی در یونیکس متناست . به طور ضمنی هر چیزی که بتوانید به آن فکر کنید یا به وسیله یک فایل متنی دیگر، یا بوسیله رابط خط فرمان (CLI) کنترل می‌شود. تنها چیزی که نمی‌توانید با یک شل اسکریپت خودکار کنید، یک برنامه یا ویژگی فقط GUIمی‌باشد. تحت یونیکس موارد خیلی زیادی از اینها وجود ندارد!

ممکن است شنیده باشید که گفته شده در ‎*nix‎، "هر چیز یک فایل است" - این درست است.

ما در این جا چند زیرفهرست داریم ... که مقصود اصلی، نکته‌ها و اشاره‌ها را دنبال می‌کنند.

اسکریپت‌نویسی CGI

کدهای خروج و کنترل جریان

نمونه جانشین Expect

کاربرد trap دانستن آن که چه‌وقت یک سیگنال توقف از قبیل‎ CTRL-C‎ و غیره دریافت کرده‌اید.

چاره‌جویی برای دوگانگی ‎'echo -n'‎ و ‎'echo \c'‎

نمونه مستند سازی شده از اسکریپت زندگی واقعی، که من نوشتم - به کاربران کمک می‌کند یک مودم SpeedTouch را پیکربندی کنند،و در آدرس http://speedtouchconf.sourceforge.net/ در دسترس می‌باشد.

ما قبلاً یک استفاده از فرمان ساده اما قدرتمند cut را نشان داده‌ایم. در این جا چند مثال از بعضی برنامه‌های خارجی رایج‌تر که استفاده می‌شوند، را بحث خواهیم نمود.

grep یک برنامه کاربردی به نهایت سودمند برای برنامه‌نویس پوسته می‌باشد.
یک مثال از grep چنین خواهد بود:


#!/bin/sh
steves=`grep -i steve /etc/passwd | cut -d: -f1`
echo "All users with the word \"steve\" in their passwd"
echo "Entries are: $steves"

اگر این اسکریپت فقط یک مورد انطباق داشته باشد، عالی است. به هرحال اگر دو سطر با کلمه "steve" در آنها، در فایل ‎ /etc/passwd‎ وجود داشته باشد، سپس پوسته محاوره‌ای این‌طور نمایش خواهد داد:

$> grep -i steve /etc/passwd 
steve:x:5062:509:Steve Parker:/home/steve:/bin/bash
fred:x:5068:512:Fred Stevens:/home/fred:/bin/bash
$> grep -i steve /etc/passwd |cut -d: -f1
steve
fred

اما در اسکریپت ما چنین خواهد بود:

Entries are: steve fred

با قرار دادن نتیجه در یک متغیر ما سطر جدید را به فاصله تغییر داده ایم، manpage(صفحه راهنمای) sh به ما می‌گویدکه اولین کاراکتر در متغیر ‎$IFS‎ برای این منظور استفاده خواهد شد. IFS به طور پیش‌فرض ‎ <space><tab><cr>‎ می باشد. شاید اگر به هرحال می‌خواستیم کاراکتر سطر جدید را نگه‌داریم: می‌توانست بهتر به نظر آید که فاصله را به سطرجدید تبدیل کنیم....این کاری برای tr است:


#!/bin/sh
steves=`grep -i steve /etc/passwd | cut -d: -f1`
echo "All users with the word \"steve\" in their passwd"
echo "Entries are: "
echo "$steves" | tr ' ' '\012'

توجه کنید که tr فاصله را به کاراکتر اکتال‎ 012 (NEWLINE)‎ تبدیل نموده.
کاربرد رایج دیگر برنامه tr استفاده آن از دامنه است... این برنامه می‌تواند حالت حروف متن را به بزرگ یا کوچک تبدیل نماید، به عنوان مثال:



#!/bin/sh
steves=`grep -i steve /etc/passwd | cut -d: -f1`
echo "All users with the word \"steve\" in their passwd"
echo "Entries are: "
echo "$steves" | tr ' ' '\012' | tr '[a-z]' '[A-Z]'

در این‌جا یک ترجمه از ‎ [a-z] ‎   به ‎ [A-Z]‎ اضافه کرده‌ایم. توجه نمایید که دقیقاًهمان تعداد کمیت دردامنه ‎ a-z ‎  وجود دارد که در ‎ A-Z‎. سپس این می‌تواند هر کاراکتر قرار گرفته در دامنه اسکی ‎ a-z‎ را به ‎ A-Z‎ ترجمه کند ... به بیان دیگر، حروف را از حالت کوچک به حالت بزرگ تبدیل کند. tr در حقیقت باهوش‌تر از این است: ‎tr [:lower:] [:upper:]‎ همان کار را به خوبی انجام می‌دهد، واحتمالاًخواناتر. همچنین این برنامه قابل حمل نیست هر tr نمی‌تواند این را انجام دهد.

حقه‌زدن

آنها که نمی‌توانند ... حقه بزنند

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

ضمن اینکه این به آن معناست که سیستم باید برنامه‌های اجرایی بزرگی( (52k برای sed و 110k برای awk) را بارگذاری کند، که انجام آن نامطبوع است، دلیل این که یک استادکار خوب ابزارش را سرزنش نمی‌کند آن است که، استادکارخوب در وهله اول از ابزارهای درست استفاده می‌کند.
بنابراین به من اجازه دهید این دو را با کاربردهای خیلی ساده معرفی کنم.

حقه‌زدن با awk

wc، را که تعداد کاراکترها، سطرها، و کلمه ها در یک فایل متن را می‌شمارد، ملاحظه کنید. خروجی‌اش چنین است:

$ wc hex2env.c
	102	189	2306	hex2env.c

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

NO_LINES=`wc -l file`

که باید تمام سطر رابخواند.
چون خروجی پر از فاصله است، نمی‌توانیم به طور امکان‌پذیری عدد 102 را در یک رشته به دست آوریم. درعوض، از این واقعیت استفاده می‌کنیم که awk به طوری مشابه با scanf در C کارمی‌کند - وفضاهای سفید ناخواسته را حذف می‌کند. و ‎ $1 $2 $3‎ وغیره را در متغیرها قرار می‌دهد. بنابراین ما از این ساختار استفاده می‌کنیم:

NO_LINES=`wc -l file | awk '{ print $1 }'`

حالا متغیر NO_LINES برابر 102 است.

حقه‌زدن با sed

برنامه سودمند دیگر sed است - ویرایشگر جریانی-. پرل در کار کردن با عبارت‌های منظم خیلی خوب است، پوسته اینطور نیست. بنابراین به سرعت می‌توانیم ساختار ‎s/from/to/g‎ را با فراخوانی sed به کار ببریم. به طور نمونه:

sed s/eth0/eth1/g file1 >  file2

تمام نمونه‌های eth0 در file1 به نمونه‌های eth1 تغییر داده و نتیجه را در file2 قرار می‌دهد
اگر می‌خواستیم فقط یک کاراکترمنفرد را تغییر بدهیم، tr ابزاری بود که استفاده می‌شد، کوچکتر بودن و بنابراین سریع‌تر برای بارگذاری .
مورد دیگر این‌که tr نمی تواند کاراکترها را از یک فایل حذف کند:

echo ${SOMETHING} | sed s/"bad word"//g

این کد، عبارت ‎ "bad word" ‎ را از متغیر ${SOMETHING} حذف می‌کند. ممکن است وسوسه شوید، که بگویید ، "اما grep می‌تواند آن را انجام دهد" - grep فقط با تمامیت سطرها کار می‌کند. فایل را ملاحظه کنید:


This line is okay.
This line contains a bad word. Treat with care.
This line is fine, too.

Grep دومین سطر را به طور کامل حذف می‌کند و فقط یک فایل دوسطری به جا می‌گذارد، sed فایل را برای خواندن تغییر می‌دهد:

This line is okay.
This line contains a . Treat with care.
This line is fine, too.

اشاره Telnet

این یک تکنیک مفید است که من از برنامه مرورگر Sun بیرون کشیدم. اگرچه مدت زیادی است که telnet در سرویس دهنده‌ها استفاده نمی‌شود، هنوز توسط برخی دستگاه‌های شبکه به کار می‌رود، از قبیل متمرکز کننده ترمینال و مشابه آن. به وسیله یک اسکریپت مانند این، اسکریپت خودتان، یا از خط فرمان، می‌توانید اجرا کنید:

$ ./telnet1.sh | telnet

افرادی در این باره از من پرسیده‌اند، و مایل بوده‌اند آنها را به طرف مجموعه کد مورد انتظار اشاره دهم، که تا حدودی پیچیده و حجیم است، این کد باید تا حدودی در میان سیستم‌ها قابل حمل باشد(مادامی که آن‌ها egrep را دارند ). اگر در سیستم شما کار نمی‌کند، استفاده از grep گنو با گزینه ‎ -q ‎ را امتحان کنید، یا یک grep اختصاصی و هدایت به ‎ /dev/null‎، به‌هرحال هنوز از نصب expect به مقدار زیادی آسان‌تر است.


telnet1.sh
#!/bin/sh
host=127.0.0.1
port=23
login=steve
passwd=hellothere
cmd="ls /tmp"

echo open ${host} ${port}
sleep 1
echo ${login}
sleep 1
echo ${passwd}
sleep 1
echo ${cmd}
sleep 1
echo exit

به هرحال Sun مقداری کد کنترل خطای هوشمند اضافه کرد( توجه داشته باشید که متغیرهایی که می‌توانید از پوسته جاری یا اسکریپت پوسته تنظیم و صادر کنید، نگهداری کلمه عبور در فایل‌های قابل خواندن را موقوف کنند ):

$ ./telnet2.sh | telnet > file1

telnet2.sh

#!/bin/sh
# telnet2.sh | telnet > FILE1 
host=127.0.0.1
port=23
login=steve
passwd=hellothere
cmd="ls /tmp"
timeout=3
file=file1
prompt="$"

echo open ${host} ${port}
sleep 1
tout=${timeout}
while [ "${tout}" -ge 0 ]
do
    if tail -1 "${file}" 2>/dev/null | egrep -e "login:" > /dev/null
    then
        echo "${login}"
        sleep 1
        tout=-5
        continue
    else
        sleep 1
        tout=`expr ${tout} - 1`
    fi
done

if [ "${tout}" -ne "-5" ]; then
  exit 1
fi

tout=${timeout}
while [ "${tout}" -ge 0 ]
do
    if tail -1 "${file}" 2>/dev/null | egrep -e "Password:" > /dev/null
    then
        echo "${passwd}"
        sleep 1
        tout=-5
        continue
    else
      if tail -1 "${file}" 2>/dev/null | egrep -e "${prompt}" > /dev/null
      then
        tout=-5
      else
        sleep 1
        tout=`expr ${tout} - 1`
      fi
    fi
done

if [ "${tout}" -ne "-5" ]; then
  exit 1
fi

> ${file}

echo ${cmd}
sleep 1
echo exit

توجه کنید با این نگارش، خروجی در فایل file1 قاپیده می‌شود، و آن فایلی است که در واقع به وسیله اسکریپت برای کنترل پیشرفتش استفاده می‌شود. من عبارت ‎"> ${file}"‎ را اضافه کرده‌ام به طوری که خروجی رسیده به داخل فایل فقط خروجی فرمان است، و فرایند اتصال همراه آن نیست.

Steve Parker  نوشته  Bourne و Bash راهنمای آموزشی اسکریپت نویسی
لطفاً برای بهتر دیدن صفحه از فایرفاکس استفاده کنید