فرمانهایی که در گروه خاصی قرار نمیگیرند
این برنامهها رشتهای از اعداد صحیح با یک مقدار افزایشی قابل انتخاب به وسیله کاربر، بیرون میدهند.
کاراکتر پیشفرض جداکننده هر عدد صحیح یک سطر جدید است، اما با استفاده از گزینه -s میتواند تغییر داده شود.
bash$ seq 5 1 2 3 4 5 bash$ seq -s : 5 1:2:3:4:5
هر دو فرمان jot، و seq در یک حلقه for به کار میآیند.
مثال 16-54. کاربرد seq برای تولید شناسههای حلقه
#!/bin/bash #کاربرد seq echo for a in `seq 80` # #همانند for a in 1 2 3 4 5 ... 80 (تایپ کردن زیادی را صرفهجویی میکند!). #استفاده از jot (در صورتیکه در سیستم شما موجود باشد) نیز ممکن است. do echo -n "$a " done # #مثال استفاده از خروجی یک فرمان برای تولید [list] در یک حلقه for echo; echo COUNT=80 #بله، seq یک پارامتر قابل تعویض هم میپذیرد. for a in `seq $COUNT` # do echo -n "$a " done # echo; echo BEGIN=75 END=80 for a in `seq $BEGIN $END` #با دادن دو شناسه، seq شمارش را از شناسه اول آغاز #+میکند و تا رسیدن به شناسه دوم ادامه میدهد. do echo -n "$a " done # echo; echo BEGIN=45 INTERVAL=5 END=80 for a in `seq $BEGIN $INTERVAL $END` #با دادن سه شناسه ، seq شمارش را از اولی شروع کرده #+شناسه دوم را برای فاصله اعداد به کار میبرد، و تا #+رسیدن به شناسه سوم ادامه میدهد. do echo -n "$a " done # echo; echo exit 0
یک مثال سادهتر:
#مجموعهای از 10 فایل، نام گذاری شده به صورت #+file.1، file.2 . . . file.10 تولید میکند. COUNT=10 PREFIX=file for filename in `seq $COUNT` do touch $PREFIX.$filename #یا میتوان عملیات دیگری از قبیل rm، grep، و غیره انجام داد. done
#!/bin/bash # #نوشته شده توسط Stefano Palmeri #با مجوز در راهنمای ABS استفاده گردیده است. #به طور مختصر توسط نگارنده ویرایش گردیده است. MINARGS=2 #اسکریپت حداقل دو شناسه لازم دارد. E_BADARGS=65 FILE=$1 let LETTERS=$#-1 #تعداد حروف تعیین شده (به عنوان شناسه خط فرمان) # show_help(){ echo echo Usage: `basename $0` file letters echo Note: `basename $0` arguments are case sensitive. echo Example: `basename $0` foobar.txt G n U L i N U x. echo } # if [ $# -lt $MINARGS ]; then echo echo "Not enough arguments." echo show_help exit $E_BADARGS fi # if [ ! -f $FILE ]; then echo "File \"$FILE\" does not exist." exit $E_BADARGS fi # for n in `seq $LETTERS`; do shift if [[ `echo -n "$1" | wc -c` -eq 1 ]]; then # echo "$1" -\> `cat $FILE | tr -cd "$1" | wc -c` # else echo "$1 is not a single char." fi done exit $? #این اسکریپت دقیقاً دارای همان کارکرد اسکریپت letter-count2.sh #+
jot برنامه سودمند کلاسیک یونیکس که تا اندازهای تواناتر از seq است، به طور معمول در یک توزیع استاندارد لینوکس گنجانده نمیشود. به هر حال بسته rpm آن جهت دانلود در MIT repository قابل دسترس است.
بر خلاف seq، برنامه jot با استفاده گزینه -r میتواند یک سری تصادفی از اعداد تولید نماید. bash$ jot -r 3 999 1069 1272 1428 |
فرمان getopt گزینههای خط فرمان دارای یک خط تیره مقدم را تجزیه میکند. این فرمان خارجی به فرمان getopts داخلی Bash شباهت دارد. به کار بردن getopt با استفاده از نشانگر -l کار کردن با گزینههای بلند را میسر میسازد.
مثال 16-56. کاربرد getopt برای تجزیه گزینههای خط فرمان
#!/bin/bash #کاربرد getopt #موقع فراخوانی این اسکریپت، موارد زیر را امتحان کنید: # # # # # # # # # # #نتایج هر یک از موارد بالا را توضیح دهید. E_OPTERR=65 if [ "$#" -eq 0 ] then #اسکریپت حداقل یک شناسه خط فرمان لازم دارد. echo "Usage $0 -[options a,b,c]" exit $E_OPTERR fi set -- `getopt "abcd:" "$@"` #پارامترهای مکانی را به شناسههای خط فرمان تنظیم میکند. #اگر شما به جای $@ از $* استفاده نمایید، چه پیش میآید؟ while [ ! -z "$1" ] do case "$1" in -a) echo "Option \"a\"";; -b) echo "Option \"b\"";; -c) echo "Option \"c\"";; -d) echo "Option \"d\" $2";; *) break;; esac shift done #به طور معمول در اسکریپت، استفاده از getopts داخلی مناسبتر است. #اسکریپت ex33.sh را ببینید. exit 0
به طوریکه Peggy Russell اشاره میکند: بیشتر اوقات برای پردازش صحیح فضای سفید و نقلقولها قرار دادن یک eval لازم است. args=$(getopt -o a:bc:d -- "$@") eval set -- "$args" |
برای یک شبیهسازی ساده شده فرمان getopt مثال 10-5 را مشاهده نمایید.
فرمان run-parts [1] تمام اسکریپتها در یک دایرکتوری هدف را، به طور متوالی به ترتیب نام فایل مرتب شده اسکی، اجرا میکند. البته، لازم است اسکریپتها دارای مجوز اجرا باشند.
سرویس cron daemon برای اجرای اسکریپتها در دایرکتوریهای /etc/cron.* فرمان run-parts را فراخوانی میکند.
فرمان yes در رفتار پیشفرضش، یک رشته متوالی از کاراکتر y دنبال شده با یک تعویض سطر را به stdout تغذیه میکند. یک control-C اجرای آن را خاتمه میدهد. یک رشته خروجی متفاوت میتواند تعیین بشود، همچون در yes different string، که به طور مداوم different string را در stdout بیرون میدهد.
شاید کسی بپرسد که مقصود از آن چیست. از خط فرمان یا در یک اسکریپت، خروجی yes میتواند به برنامهای که در انتظار ورودی کاربر است، لولهکشی یا تغییر مسیر داده شود. در نتیجه، این نوعی نگارش ضعیف از expect میشود.
yes | fsck /dev/hda1 فرمان fsck را به طور غیر محاورهای اجرا میکند (احتیاط!).
yes | rm -r dirname دارای همان نتیجه rm -rf dirname است (احتیاط!).
موقع لولهکشی yes به یک فرمان سیستمی بالقوه پر مخاطره، از قبیل fsck یا fdisk احتیاط شرط عقل است. این کار میتواند دارای نتایج پیشبینی نشده باشد. |
فرمان yes متغیرها را تجزیه میکند، یا به طور دقیقتر، متغیرهای تجزیه شده را بازتاب میدهد. برای مثال:
bash$ yes $BASH_VERSION 3.1.17(1)-release 3.1.17(1)-release 3.1.17(1)-release 3.1.17(1)-release 3.1.17(1)-release . . . این «ویژگی» خاص ممکن است برای تولید فوری یک فایل اسکی بسیار بزرگ به کار برود: bash$ yes $PATH > huge_file.txt Ctl-Cبه طور بسیار سریع Ctl-C را بزنید، یا آنکه ممکن است فایلی بزرگتر از آنچه توقع داشتید به دست بیاورید. |
فرمان yes میتواند در یک تابع اسکریپت بسیار ساده شبیهسازی بشود.
yes () { #شبیهسازی ناقابل yes local DEFAULT_TEXT="y" while [ true ] #یک حلقه بی پایان. do if [ -z "$1" ] then echo "$DEFAULT_TEXT" else # echo "$1" # fi done #تنها موارد غایب، گزینههای --help و --version هستند. }
با استفاده از یک کاراکتر ASCII (پیشفرض #) شناسهها را به صورت یک banner عمودی بزرگ در stdout نمایش میدهد. این خروجی میتواند جهت دریافت نسخه کاغذی به یک چاپگر تغییر مسیر داده شود.
توجه نمایید که banner احتمالاً به دلیل آن که دیگر مفید به حساب نمیآید از بسیاری توزیعهای لینوکس حذف گردیده است.
تمام متغیرهای محیطی تنظیم شده برای یک کاربر خاص را نمایش میدهد.
bash$ printenv | grep HOME HOME=/home/bozo
فرمانهای lp و lpr، فایل(ها) را برای چاپ شدن به صورت یک نسخه چاپی، به صف چاپ [2]میفرستند. منشاء نام این فرمانها به چاپگرهای خطی یک دوران دیگر باز میگردد. [3]
bash$ lp file1.txt یا bash lp <file1.txt
بیشتر اوقات، لولهکشی خروجی قالببندی شده فرمان pr به lp مفید است.
bash$ pr -options file1.txt | lp
برنامههای قالببندی، از قبیل groff و Ghostscript میتوانند خروجیشان را به طور مستقیم به lp بفرستند.
bash$ groff -Tascii file.tr | lp bash$ gs -options | lp file.ps
فرمانهای مرتبط، عبارتند از: lpq، برای نمایش صف چاپ، و lprm، برای حذف کارها از صف چاپ.
[یونیکس یک ایده از عمل لولهکشی گذرگاهها اقتباس میکند.]
این یک عملگر تغییر مسیر، اما با یک تفاوت است. همانند سه راهی لولهکشی، این فرمان «هدایت کردن» خروجی فرمان یا فرمانها از داخل یک لوله به یک فایل، اما بدون اثر گذاری بر روی نتیجه را اجازه میدهد. برای چاپ کردن یک پردازش درحال پیشرفت در یک فایل یا کاغذ، شاید برای پیگردی آن پردازش به منظور اشکالزدایی، سودمند است.
(تغییر مسیر) |----> به فایل | ===========================|==================== command ---> command ---> | tee ---> command ---> ---> خروجی لوله =============================================== |
cat listfile* | sort | tee check.file | uniq > result.file # #فایل check.file قبل از اینکه سطرهای تکراری توسط فرمان uniq #+حذف گردند، شامل «listfile»های مرتب شده بهم پیوسته میشود.
مترجم: بدون در نظر گرفتن بخش | tee check.file در سطر فرمان فوق، عملکرد آن الحاق فایلهای listfile و تحویل نتیجه آن به فرمان sort برای مرتب نمودن این خروجی و تحویل نتیجه حاصله به فرمان uniq بود که این فرمان نیز سطرهای تکراری را حذف نموده و خروجی را با تغییر مسیر به فایل result.file ارسال مینمود.
اکنون نیز همین کار صورت گرفته است. اما با این تفاوت که در بین راه قبل از تحویل خروجی به فرمان uniq، خروجی به tee check.file نیزداده میشود و در عین حال بدون هرگونه تغییر به راه خود در لوله ادامه میدهد. مشابه لولهکشی آب هست، اما قدری تفاوت دارد. بر خلاف آب، در محل انشعاب چیزی از خروجی کم نمیشود.
این فرمان گمنام، یک لوله با نام، یک بافر اولین ورودی-اولین خروجی موقتی برای انتقال دادهها مابین پردازشها، تولید میکند. [4] به طور عادی، یک پردازش در FIFO مینویسد، و دیگری از آن میخواند. مثال A-14 را ببینید.
#!/bin/bash #این اسکریپت کوتاه توسط Omair Eshkenazi نوشته شده. #با مجوز در راهنمای ABS استفاده گردیده (با تشکر!). mkfifo pipe1 #بله، لولهها میتوانند نامیده شوند. mkfifo pipe2 #عنوان «لوله با نام» از این جهت است. (cut -d' ' -f1 | tr "a-z" "A-Z") >pipe2 <pipe1 & ls -l | tr -s ' ' | cut -d' ' -f3,9- | tee pipe1 | cut -d' ' -f2 | paste - pipe2 rm -f pipe1 rm -f pipe2 #وقتی اسکریپت خاتمه مییابد، kill کردن پردازشهای پسزمینه لازم نیست(چرا؟). exit $?
اکنون، فراخواندن اسکریپت و نمایش خروجی[7]:
sh mkfifo-example.sh 4830.tar.gz BOZO pipe1 BOZO pipe2 BOZO mkfifo-example.sh BOZO Mixed.msg BOZO
این فرمان اعتبار یک نام فایل را بررسی میکند. اگر نام فایل از حداکثر طول مجاز (255 کاراکتر) تجاوز نماید یا یک یا چندتا از دایرکتوریها در مسیرش قابل جستجو نباشد، آنوقت یک پیغام خطا نتیجه میشود.
متاسفانه، pathchk یک کد خطای قابل تشخیص برگشت نمیدهد، و بنابراین، تقریباً در یک اسکریپت بلااستفاده است . به جای آن عملگرهای بررسی فایل را در نظر بگیرید.
اگر چه این فرمان تا اندازهای ناشناس و قدیمی data duplicator(رونوشت برداری دادهها) از برنامهای برای مبادله دادهها بین کامپیوترهای کوچک یونیکس و کامپیوترهای بزرگ آی بی ام (IBM mainframes) بر روی نوارهای مغناطیسی سرچشمه گرفته است، بازهم موارد استفادهاش را دارد. فرمان dd به سادگی، اما با تبدیل، یک فایل (یا stdin/stdout) را کپی میکند. تبدیلها شامل ASCII/EBCDIC [5]، حالت کوچک و بزرگ حروف، مبادله جفت بایتها میان ورودی وخروجی، و پریدن و-یا کوتاه کردن ابتدا یا انتهای فایل ورودی میگردد.
#تبدیل تمام فایل به حروف بزرگ: dd if=$filename conv=ucase > $filename.uppercase # #
برخی گزینههای اصلی برای dd عبارتند از:
if=INFILE
INFILE فایل مبداء است.
of=OUTFILE
OUTFILE فایل مقصد است، فایلی که دادهها در آن نوشته خواهند شد.
bs=BLOCKSIZE
این گزینه، اندازه هر بلوک از دادهها است که خوانده یا نوشته میشود، به طور معمول توانی از عدد 2 است.
skip=BLOCKS
تعداد بلوکهای داده برای پرش از آنها در INFILE قبل از شروع عمل کپی. این گزینه موقعی که INFILE دارای «دادههای ناخواسته» یا دادههای آشفته در سرآیندش باشد یا وقتی که تنها کپی قسمتی از INFILE مورد نظر باشد، مفید است.
seek=BLOCKS
تعداد بلوکهای داده برای پرش در OUTFILE قبل از شروع کپی، رها کردن فضای خالی از داده در ابتدای OUTFILE.
count=BLOCKS
فقط کپی این تعداد بلوک از دادهها، به جای تمام INFILE.
conv=CONVERSION
نوع تبدیل برای اعمال شدن روی دادههای INFILE قبل از نوشتن در OUTFILE.
یک فرمان dd --help تمام گزینههایی را که این برنامه سودمند قدرتمند میپذیرد لیست میکند.
مثال 16-57. اسکریپتی که خودش را کپی میکند
#!/bin/bash # # file_subscript=copy dd if=$0 of=$0.$file_subscript 2>/dev/null # exit $? # #+توسط Willard Quine یک quine نامیده میشود. #آیا این اسکریپت واجد شرایط یک quine هست؟
#!/bin/bash # #اسکریپت توسط Stephane Chazelas نوشته شده است. #اندکی توسط مولف راهنمای ABS ویرایش گردیده است. infile=$0 # outfile=log.txt # n=8 p=11 dd if=$infile of=$outfile bs=1 skip=$((n-1)) count=$((p-n+1)) 2> /dev/null #کاراکترهای n تا p (8 تا 11) از این اسکریپت (bash) را استخراج میکند. # echo -n "hello vertical world" | dd cbs=1 conv=unblock 2> /dev/null #عبارت «hello vertical world» را به طور عمودی به طرف پایین بازتاب میدهد. #چرا؟ چون هر کاراکتری را که dd صادر میکند، یک سطر جدید دنبال میکند. #exit $? مترجم: با وجود تبدیل conv=unblock پس از هر cbs-size (در اینجا یک بایت است)، یک سطر جدید درج میشود
برای اثبات تجربی اینکه dd چطور همهفن حریف است، بیایید از آن برای اخذ ضربه کلیدها استفاده کنیم.
مثال 16-59. ضبط کردن ضربه کلیدها
#!/bin/bash # ضبط ضربه کلیدها بدون نیاز به فشردن ENTER. keypresses=4 # old_tty_setting=$(stty -g) # echo "Press $keypresses keys." stty -icanon -echo # # keys=$(dd bs=1 count=$keypresses 2> /dev/null) #در صورتیکه if(فایل ورودی) مشخص نشود dd از stdin استفاده میکند. stty "$old_tty_setting" # echo "You pressed the \"$keys\" keys." #با تشکر از Stephane Chazelas برای نشان دادن این روش. exit 0
فرمان dd میتواند دستیابی غیر ترتیبی به یک جریان داده را انجام بدهد.
echo -n . | dd bs=1 seek=4 of=file conv=notrunc ## مترجم: به طور مستقیم کاراکتر echo شده را روی بایت 5 فایل مینویسد گزینه conv=notrunc به معنی آن است که #+فایل خروجی کوتاهسازی نخواهد شد . #با تشکر از S.C.
فرمان dd میتواند دادههای خام یا تصویر دیسکها را به (یا از) دستگاههایی مانند گردانندههای دیسک نرم یا نوارهای مغتاطیسی کپی کند (مثال A-5). یک مورد استفاده رایج آن، ایجاد فلاپیهای بوت شدنی است.
dd if=kernel-image of=/dev/fd0H1440
به طور مشابهی، dd میتواند تمام محتویات یک دیسک نرم، حتی فرمت شده با یک سیستم عامل «بیگانه» را به صورت یک فایل image به دیسک سخت کپی کند.
dd if=/dev/fd0 of=/home/bozo/projects/floppy.img
بعلاوه، dd میتواند فلاش دیسکها و کارتهای SD بوت شدنی تولید کند.
dd if=image.iso of=/dev/sdb
مثال 16-60. آمادهسازی یک کارت SD قابل بوت شدن برای Raspberry Pi
#!/bin/bash # #آماده کردن یک کارت SD با یک image قابل بوت برای Raspberry Pi # # #در غیر اینصورت از پیشفرضها استفاده میشود. DEFAULTbs=4M #اندازه بلوک، 4 mb پیشفرض. DEFAULTif="2013-07-26-wheezy-raspbian.img" #توزیع به طور معمول مورد استفاده. DEFAULTsdcard="/dev/mmcblk0" #میتواند متفاوت باشد، بررسی کنید! ROOTUSER_NAME=root #باید به عنوان کاربر ارشد اجرا شود! E_NOTROOT=81 E_NOIMAGE=82 username=$(id -nu) #چه کسی این اسکریپت را اجرا میکند؟ if [ "$username" != "$ROOTUSER_NAME" ] then echo "This script must run as root or with root privileges." exit $E_NOTROOT fi if [ -n "$1" ] then imagefile="$1" else imagefile="$DEFAULTif" fi if [ -n "$2" ] then sdcard="$2" else sdcard="$DEFAULTsdcard" fi if [ ! -e $imagefile ] then echo "Image file \"$imagefile\" not found!" exit $E_NOIMAGE fi echo "Last chance to change your mind!"; echo read -s -n1 -p "Hit a key to write $imagefile to $sdcard [Ctl-c to exit]." echo; echo echo "Writing $imagefile to $sdcard ..." dd bs=$DEFAULTbs if=$imagefile of=$sdcard exit $? # # #(1 کنترل خطای اضافی را فراهم کنید. #(2 ایجاد تشخیص خودکار فایل دستگاه کارت SD در اسکریپت (دشوار!). #(3 ایجاد تشخیص خودکار فایل تصویر(*img) در $PWD توسط اسکریپت.
سایر کاربردهای dd شامل مقداردهی اولیه فایلهای موقت swap (مثال 31-2) و ramdiskها (مثال 31-3) است. حتی میتواند یک کپی سطح پایین از کل یک پارتیشن دیسک سخت انجام بدهد، اگر چه لزوماً این پیشنهاد نمیشود.
برخی افراد (که احتمالاً کار بهتری برای صرف وقتشان ندارند) به طور دایم در حال اندیشیدن به کاربردهای جالب dd هستند.
مثال 16-61. حذف کردن یک فایل به طور امن
#!/bin/bash # # #+ # #+ PASSES=7 # # #+ BLOCKSIZE=1 #I/O با /dev/urandom به اندازه بلوک 1 #+ E_BADARGS=70 # E_NOT_FOUND=71 E_CHANGED_MIND=72 if [ -z "$1" ] # then echo "Usage: `basename $0` filename" exit $E_BADARGS fi file=$1 if [ ! -e "$file" ] then echo "File \"$file\" not found." exit $E_NOT_FOUND fi echo; echo -n "Are you absolutely sure you want to blot out \"$file\" (y/n)? " read answer case "$answer" in [nN]) echo "Changed your mind, huh?" exit $E_CHANGED_MIND ;; *) echo "Blotting out file \"$file\".";; esac flength=$(ls -l "$file" | awk '{print $5}') #فیلد 5 طول فایل است. pass_count=1 chmod u+w "$file" # echo while [ "$pass_count" -le "$PASSES" ] do echo "Pass #$pass_count" sync # dd if=/dev/urandom of=$file bs=$BLOCKSIZE count=$flength # sync # dd if=/dev/zero of=$file bs=$BLOCKSIZE count=$flength # sync # let "pass_count += 1" echo done rm -f $file # sync # echo "File \"$file\" blotted out and deleted."; echo exit 0 # #+ #فرمان shred که بخشی از بسته «fileutils» گنو است، هر چند #+ #فایل با روشهای معمولی نمیتواند «undelete» یا بازیابی گردد # #+ #+ #این اسکریپت ممکن است با یک سیستمفایل jfs خوب عمل نکند. #تمرین (دشوار): آن را برای برطرف نمودن این نقص، اصلاح کنید. #بسته wipe حذف فایل Tom Vier کار shred کردن کامل فایل را #+ # # #+Peter Gutmann تحت عنوان زیر را ملاحظه نمایید. #+ #
همچنین، مدخل dd thread در فهرست کتابها را ببینید.
فیلتر od یا octal dump، ورودی (یا فایلها) را به اکتال (مبنای 8) یا مبناهای دیگر تبدیل میکند. این فیلتر برای مشاهده یا پردازش فایلهای داده باینری یا فایلهای دستگاه غیر قابل خواندن سیستم از قبیل /dev/urandom، و به عنوان یک فیلتر برای دادههای باینری سودمند است.
head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p' #خروجی نمونه: 1324725719, 3918166450, 2989231420 و غیره. #از اسکریپت مثال rnd.sh، توسط Stéphane Chazelas
همچنین مثال 9-16 و مثال A-36 را ببینید.
یک رونوشتبرداری هگزادسیمال، اکتال، دسیمال، یا ASCII از یک فایل باینری انجام میدهد. این فرمان کمابیش معادل فرمان od فوق است، اما تقریباً بدون استفاده است. شاید در ترکیب با dd و less برای دیدن محتویات یک فایل باینری به کار برود.
dd if=/bin/ls | hexdump -C | less #گزینه -C به طور زیبایی خروجی را در شکل جدولی قالببندی میکند.
اطلاعات در باره یک فایل object یا باینری قابل اجرا را در قالب هگزادسیمال یا به صورت یک لیستگیری پیاده شده(disassembled) (با گزینه -d) نمایش میدهد.
bash$ objdump -d /bin/ls /bin/ls: file format elf32-i386 Disassembly of section .init: 080490bc <.init>: 80490bc: 55 push %ebp 80490bd: 89 e5 mov %esp,%ebp . . .
این فرمان یک «magic cookie»، یک عدد هگزادسیمال شبهتصادفی ۱۲۸ بیتی (۳۲ کاراکتر) تولید میکند که به طور معمول به عنوان یک «علامت مشخصه» اجازه دادن به وسیله خادم X به کار میرود. همچنین برای استفاده در یک اسکریپت به عنوان یک عدد تصادفی «سریع و کم هزینه» نیز مفید است.
random000=$(mcookie)
البته، یک اسکریپت میتواند از md5sum برای همین منظور استفاده نماید.
#تولید مجموع مقابلهای(checksum) md5 روی خود اسکریپت. random001=`md5sum $0 | awk '{print $1}'` #از awk برای درآوردن نام فایل استفاده میکند.
فرمان mcookie روش دیگری برای تولید نام فایل «منحصر به فرد» ارایه میکند.
مثال 16-62. تولید کننده نام فایل
#!/bin/bash # BASE_STR=`mcookie` #magic cookie سی و دو کاراکتری. POS=11 #محل انتخابی در رشته magic cookie LEN=5 #گرفتن تعداد $LEN کاراکتر متوالی. prefix=temp #به هر حال، این یک فایل موقت است. #برای «یکتایی» بیشتر، پیشوند نامفایل #+را با به کار بردن همان روش تولید #+پسوند پایین تولید نمایید. suffix=${BASE_STR:POS:LEN} #بیرون کشیدن یک رشته 5 کاراکتری که #+از موقعیت 11 شروع میشود. temp_filename=$prefix.$suffix #ساختن نام فایل. echo "Temp filename = "$temp_filename"" exit 0bash$ sh tempfile-name.sh Temp filename = temp.e19ea#این روش تولید نامفایل «یکتا» را با روش date در ex51.sh مقایسه کنید.
این برنامه سودمند واحدهای اندازه مختلف را به یکدیگر تبدیل میکند . در حالیکه، به طور معمول در وضعیت محاورهای فراخوانی میگردد، units ممکن است در یک اسکریپت نیز مورد استفاده بیابد.
مثال 16-63. تبدیل متر به مایل
#!/bin/bash # #باید برنامه units نصب شده باشد. convert_units () #واحدها برای تبدیل را به عنوان شناسه میپذیرد. { cf=$(units "$1" "$2" | sed --silent -e '1p' | awk '{print $2}') #بیرون آوردن هر چیزی غیر از عامل واقعی تبدیل. echo "$cf" } Unit1=miles Unit2=meters cfactor=`convert_units $Unit1 $Unit2` quantity=3.73 result=$(echo $quantity*$cfactor | bc) echo "There are $result $Unit2 in $quantity $Unit1." #اگر واحدهای ناسازگار از قبیل acres(یک واحد سطح) و مایل #+ exit 0 #تمرین: این اسکریپت را برای پذیرش پارامترهای خط فرمان، #البته همراه با کنترل خطای متناسب، ویرایش نمایید.
یک گنج پنهان، m4 یک فیلتر پردازش ماکرو [6] قدرتمند، واقعاً یک زبان کامل است. هرچند که در اصل به عنوان یک پیشپردازشگر برای RatFor نوشته شد، m4 لباس سودمند بودن به عنوان یک برنامه خودکفا را بر تن نمود. در حقیقت، m4 برخی از تواناییهای eval، tr، و awk را با امکانات بسط ماکروی گستردهاش ترکیب میکند.
شماره آوریل 2002 نشریه Linux Journal دارای یک مبحث بسیار دقیق در مورد m4 و موارد استفاده آن است.
#!/bin/bash # # string=abcdA01 echo "len($string)" | m4 # echo "substr($string,4)" | m4 # echo "regexp($string,[0-1][0-1],\&Z)" | m4 # # var=99 echo "incr($var)" | m4 # echo "eval($var / 3)" | m4 # exit
این گونه مبتنی بر X از echo یک پنجره پیغام-پرسوجو در میز کار ظاهر میکند.
xmessage Left click to continue -button okay
برنامه سودمند zenity برای نمایش widgetهای محاوره GTK+ تنظیم گردیده و برای اهداف اسکریپتنویسی بسیار مناسب است.
فرمان doexec امکان عبور دادن یک فهرست انتخابی از شناسهها را به فایل اجرایی باینری فراهم میکند. مخصوصاً، عبور دادن argv[0] (که مطابق است با $0 در یک اسکریپت) اجازه میدهد فایل اجرایی توسط چند نام فراخوانی گردد، و آنوقت میتواند مجموعههای مختلفی از عملیات را بر اساس نامی که با آن فراخوانی شده، انجام بدهد. آنچه نتیجه میشود، روش غیرمستقیم عبور دادن گزینهها به یک فایل اجرایی است.
برای مثال، دایرکتوری /usr/local/bin میتواند شامل یک فایل باینری به نام aaa باشد. فراخوانی doexec /usr/local/bin/aaa list تمام فایلها در دایرکتوری کاری جاری را که با یک «a» شروع میشوند list خواهد نمود، در حالیکه فراخوانی doexec /usr/local/bin/aaa delete (همان فایل اجرایی با delete) آن فایلها را delete خواهد نمود.
رفتارهای متفاوت فایل اجرایی باید در داخل خود کد قابل اجرا تعیین بشود، قابل قیاس با موردی مانند پایین در یک اسکریپت پوسته:
case `basename $0` in "name1" ) do_something;; "name2" ) do_something_else;; "name3" ) do_yet_another_thing;; * ) bail_out;; esac |
ابزارهای خانواده dialog روشی برای احضار کردن کادرهای محاورهای «dialog» از داخل یک اسکریپت فراهم مینمایند. گونههای پیچیدهتر dialog -- gdialog، Xdialog، و kdialog -- در واقع widgetهای پنجرههای X را فراخوانی میکنند.
فرمان sox، یا «sound exchange» نواختن فایلهای صوتی و تبدیل آنها را انجام میدهد. در حقیقت، فایل اجرایی /usr/bin/play ( در حال حاضر منسوخ) چیزی غیراز یک لفاف پوسته برای sox نیست.
برای مثال، sox soundfile.wav soundfile.au یک فایل صوتی WAV را به یک فایل صوتی AU (قالب صوتی Sun) تبدیل میکند.
اسکریپتهای پوسته به طور مطلوبی مناسب عملیات پردازش دستهای sox روی فایلهای صوتی هستند. برای مثال، Linux Radio Timeshift HOWTO و MP3do Project را ملاحظه کنید.
[1] | این در حقیقت یک اسکریپت وفق داده شده برای توزیع دبیان لینوکس است. |
[2] | صف چاپ، گروهی از کارهای «در حال انتظار» برای چاپ شدن است. |
[3] | چاپگرهای خطی مکانیکی بزرگ، در هر زمان یک سطر منفرد از نمونه را با همنوازی مقدار قابل ملاحظهای سر و صدا روی صفحههای بهم پیوسته کاغذ greenbar (کاغذ دارای نوارهای سبز و سفید) چاپ میکردند. به خروجی کاغذیِ بدینگونه چاپ شده، به عنوان یک نتیجه نهایی مراجعه میشد. |
[4] | برای یک مرور اجمالی بسیار خوب از این مبحث، گفتار Andy Vaught، مقدمهای بر لولههای بانام، در شماره سپتامبر 1997 نشریه Linux Journal را ملاحظه نمایید. |
[5] | EBCDIC (تلفظ شده به صورت «ebb-sid-ick») یک سرنام برای «Extended Binary Coded Decimal Interchange Code»، یک قالب داده غیر رایج IBM، است. یک کاربرد نا آشنای گزینه conv=ebcdic فرمان dd مانند یک کد کننده سریع و آسان فایل متن است، اما خیلی امن نیست. cat $file | dd conv=swab,ebcdic > $file_encrypted # # |
[6] | یک macro یک ثابت نمادین است که به یک رشته فرمان یا مجموعهای از عملیات روی پارامترها بسط مییابد. به سادگی آن را همچون یک میانبر یا مخفف تعبیر کنید. |
[7] | این اسکریپت ظاهراً پیچیده مینماید. اما در صورتی که با عملکرد ابزارهای به کار رفته در آن آشنایی مناسبی وجود داشته باشد چندان پیچیده نخواهد بود. bash$ ls -l -rw-rw-r-- 1 bozo bozo 440 Jun 30 16:59 mkfifo-example.sh ابتدا با استفاده از فرمان mkfifo دو لولهبانام pipe1 و pipe2 ایجاد میگردد. در این مرحله خواهیم داشت: bash$ ls -l -rw-rw-r-- 1 bozo bozo 440 Jun 30 16:59 mkfifo-example.sh prw-rw-r-- 1 bozo bozo 0 Jun 30 17:57 pipe1 prw-rw-r-- 1 bozo bozo 0 Jun 30 17:57 pipe2 اما من در ادامه باز هم برای سهولت، این دو سطر اخیر خروجی را نیز نادیده خواهم گرفت و فرض میکنم خروجی فرمان ls در زمان اجرا همان یک سطر اول خواهد بود و توضیح را بر این فرض بنا میکنم.
# (cut -d' ' -f1 | tr "a-z" "A-Z") >pipe2 <pipe1 & # در سطر نخست، بخش داخل پرانتز یک خط لوله را تشکیل میدهد که بواسطه <pipe1 از pipe1 میخواند و بواسطه >pipe2 در pipe2 مینویسد. با استفاده از کاراکتر & این سطر در پسزمینه قرار داده شده که منتظر میماند تا دادهای به لوله با نام pipe1 وارد شود و جریان یافته و از pipe2 خارج شود. اکنون تا قبل از اجرای سطر دوم در اینجا هیچ جریانی برقرار نیست و کار خاصی انجام نمیشود (خط لولهای ایجاد شده ولی دادهای در آن جریان ندارد). بنابراین توضیح را از سطر دوم ادامه میدهیم: mkfifo-example.sh BOZO pipe1 BOZO pipe2 BOZO چون هنگامی که اسکریپت دستور ls -l را اجرا میکند دو لوله با نام pipe1 و pipe2 نیز در دایرکتوری کاری ایجاد گردیدهاند و در لیستگیری ظاهر میشوند. |