جایگزینی فرمان

فصل ‎12‎- جایگزینی فرمان

جایگزینی فرمان، خروجی یک فرمان ‎[1]‎ یا حتی چندین فرمان را دوباره تخصیص می‌دهد، یعنی خروجی فرمان را بدون کم و کاست به یک مضمون دیگر متصل می‌کند. ‎[2]‎

شکل کلاسیک جایگزینی فرمان، از نقل‌قول‌های برعکس (`...`) استفاده می‌کند. فرمانهای داخل نقل‌قول‌های برعکس ‎(backticks)‎ متن سطرفرمان به وجود می‌آورند.

script_name=`basename $0`
echo "The name of this script is $script_name."

خروجی فرمان می‌تواند به عنوان شناسه‌های یک فرمان دیگر، برای تنظیم یک متغیر، و حتی برای تولید لیست شناسه‌ها در یک حلقه for به کار برود.

rm `cat filename`         # ‎"filename"‎ شامل لیستی از فایلها جهت حذف شدن است.
#
#        ‎S. C.‎ اشاره می‌کند که ممکن است به خطای ‎"arg list too long"‎ منجر بشود.
#				         ‎xargs rm -- < filename‎ مناسب‌تر است. 
# ( ‎--‎ آن مواردی را پوشش می‌دهد که در آنها ‎"filename"‎ با یک ‎"-"‎ شروع می‌شود )

textfile_listing=`ls *.txt`
#                  متغیر شامل نام تمام فایلهای ‎*.txt‎ در دایرکتوری جاری می‌شود.
echo $textfile_listing

textfile_listing2=$(ls *.txt)                # 
echo $textfile_listing2                      #                  

#    
#                            
#
#
#    #
#
#
#  با تشکر از ‎S.C.‎

جایگزینی فرمان یک پوسته فرعی احضار می‌کند.


Caution

جایگزینی فرمان ممکن است منجر به تفکیک کلمه بشود.

COMMAND `echo a b`     #  ‎2‎ شناسه: a و b

COMMAND "`echo a b`"   #  ‎1‎ شناسه: ‎"a b"‎

COMMAND `echo`         #

COMMAND "`echo`"       #

#  با تشکر از ‎S.C.‎

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

##
#                                    

mkdir 'dir with trailing newline
'

cd 'dir with trailing newline
'

cd "`pwd`"                   # 
#

cd "$PWD"                    #



old_tty_setting=$(stty -g)   #             
echo "Hit a key "
stty -icanon -echo           #  لغو کردن وضعیت ‎"canonical"‎ برای ترمینال.
                             #    همچنین غیر فعال کردن تنظیم «محلی» echo
key=$(dd bs=1 count=1 2> /dev/null)    #استفاده از dd جهت ضبط ضربه‌کلید.
stty "$old_tty_setting"      #                   
echo "You hit ${#key} key."  
#      ‎${#variable}‎ مساوی تعداد کاراکترها در ‎$variable‎ است.
#
# با زدن هر کلیدی غیر از اینتر، خروجی ‎"You hit 1 key."‎ است.
#               با زدن اینتر، خروجی‌اش ‎"You hit 0 key."‎ است.
#                
#قطعه کد توسط ‎Stéphane Chazelas‎.


Caution

استفاده از فرمان echo برای برونداد یک متغیر غیر نقل‌قولی تنظیم شده با جایگزینی فرمان، کاراکترهای سطر جدید انتهایی را از خروجی فرمان(های) تخصیص یافته حذف می‌کند. این مطلب می‌تواند باعث غافل‌گیری ناخوشایندی بشود.

dir_listing=`ls -l`
echo $dir_listing          # 

#
#         

#
#

#                    


echo "$dir_listing"        # 
#
#
#
#

جایگزینی فرمان حتی تنظیم یک متغیر به محتوای یک فایل را با استفاده از تغییر مسیر یا فرمان cat جایز می‌کند.

variable1=`<file1`        #   تنظیم متغیر ‎variable1‎ به محتویات فایل ‎file1‎
variable2=`cat file2`     #  تنظیم متغیر ‎variable2‎ به محتویات فایل ‎file2‎
                          #    به هرحال، این یک پردازش جدید منشعب می‌کند,
                          #+

             # 
             #+     

             #             
echo "` <$0`"          # 

#  برگزیده از فایل سیستمی ‎/etc/rc.d/rc.sysinit‎ (در یک سیستم لینوکس ردهت)


if [ -f /fsckoptions ]; then
        fsckoptions=`cat /fsckoptions`
...
fi
#
#
if [ -e "/proc/ide/${disk[$device]}/media" ] ; then
             hdmedia=`cat /proc/ide/${disk[$device]}/media`
...
fi
#
#
if [ ! -n "`uname -r | grep -- "-"`" ]; then
       ktag="`cat /proc/version`"
...
fi
#
#
if [ $usb = "1" ]; then
    sleep 5
    mouseoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=02"`
    kbdoutput=`cat /proc/bus/usb/devices 2>/dev/null|grep -E "^I.*Cls=03.*Prot=01"`
...
fi

Caution

یک متغیر را به محتوای یک فایل متن طولانی تنظیم نکنید، مگر اینکه دلیل بسیار خوبی برای انجام آن داشته باشید. متغیر را به محتویات یک فایل binary تنظیم نکنید، حتی به عنوان یک شوخی.

مثال ‎12-1‎. ترفندهای اسکریپت نابخردانه

#!/bin/bash
#
# از جلد اول ‎"Stupid Script Tricks"‎ .

exit 99  ###    

dangerous_variable=`cat /boot/vmlinuz`   #

echo "string-length of \$dangerous_variable = ${#dangerous_variable}"
#       طول رشته ‎$dangerous_variable‎ مساوی ‎794151‎ است.
#                         (کرنل‌های جدید بزرگتر هستند.)
# با ‎'wc -c /boot/vmlinuz'‎ همان تعداد را ارایه نمی‌کند.

#
#


#

exit 0

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

جایگزینی فرمان تنظیم یک متغیر به خروجی یک حلقه را اجازه می‌دهد. کلید این کار در تصرف خروجی یک فرمان echo در داخل حلقه است.

مثال ‎12-2‎. تولید یک متغیر از یک حلقه

#!/bin/bash
#

variable1=`for i in 1 2 3 4 5
do
  echo -n "$i"                        #   فرمان ‎'echo'‎ در اینجا برای
done`                                 #+ 

echo "variable1 = $variable1"         #        


i=0
variable2=`while [ "$i" -lt 10 ]
do
  echo -n "$i"                        #      دوباره، ‎'echo'‎ ضروری.
  let "i += 1"                        #                  
done`

echo "variable2 = $variable2"         #   

#    

exit 0


نوع ‎$(...)‎ جایگزینی فرمان، نقل‌قولهای برعکس برای جایگزینی فرمان را از اعتبار انداخته است.

output=$(sed -n /"$1"/p $file)   #		   از مثال ‎"grp.sh"‎
	      
#        		    
File_contents1=$(cat $file1)      
File_contents2=$(<$file2)        # ‎Bash‎ این مورد را نیز اجازه می‌دهد.

نوع ‎$(...)‎ جایگزینی فرمان، با backslash دوتایی به روشی غیر از ‎`...`‎ رفتار می‌کند.

bash$ echo `echo \\`


bash$ echo $(echo \\)
\

شکل ‎$(...)‎ جایگزینی فرمان، تودرتویی را اجازه می‌دهد. ‎[3]‎

word_count=$( wc -w $(echo * | awk '{print $8}') )

یا برای موردی تا اندازه‌ای پیچیده‌تر . . .

مثال ‎12-3‎. یافتن مقلوبی‌ها

#!/bin/bash
#
#

#     از برنامه سودمند ‎"anagram"‎ که قسمتی از بسته
#+  لیست کلمه ‎"yawl"‎ نگارنده است، استفاده می‌کند.
#
#

E_NOARGS=86
E_BADARG=87
MINLEN=7

if [ -z "$1" ]
then
  echo "Usage $0 LETTERSET"
  exit $E_NOARGS         #
elif [ ${#1} -lt $MINLEN ]
then
  echo "Argument must have at least $MINLEN letters."
  exit $E_BADARG
fi



FILTER='.......'         #
#
Anagrams=( $(echo $(anagram $1 | grep $FILTER) ) )
#
#

echo
echo "${#Anagrams[*]}  7+ letter anagrams found"
echo
echo ${Anagrams[0]}      #
echo ${Anagrams[1]}      #
                         #

# #     

#  

# همچنین برای یک تمرین در مورد کشف مقلوبی، اسکریپت ‎agram.sh‎ را ببینید.

exit $?

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

  1. مثال ‎11-8‎

  2. مثال ‎11-27‎

  3. مثال ‎9-16‎

  4. مثال ‎16-3‎

  1. مثال ‎16-22‎

  2. مثال ‎16-17‎

  3. مثال ‎16-54‎

  4. مثال ‎11-14‎

  1. مثال ‎11-11‎

  2. مثال ‎16-32‎

  3. مثال ‎20-8‎

  4. مثال ‎A-16‎

  1. مثال ‎29-3‎

  2. مثال ‎16-47‎

  3. مثال ‎16-48‎

  4. مثال ‎16-49‎

یادداشت‌ها

[1]

از منظر جایگزینی فرمان، یک فرمان می‌تواند یک فرمان خارجی سیستم، یک builtin داخلی اسکریپت‌نویسی، یا حتی یک تابع اسکریپت باشد.

[2]

در یک مفهوم از نظر تکنیکی صحیح‌تر، جایگزینی فرمان stdout یک فرمان را استخراج کرده، سپس آن را با استفاده از عملگر = به یک متغیر تخصیص می‌دهد.

[3]

در واقع، تودرتویی با نقل‌قولهای برعکس نیز ممکن است، اما همانطورکه ‎John Default‎ اشاره می‌کند، فقط با معاف کردن (escaping) نقل‌قولهای برعکس درونی.

word_count=` wc -w \`echo * | awk '{print $8}'\` `