جایگزینی پارامتر

فصل ‎10‎- دستکاری متغیرها

‎10.2‎- جایگزینی پارامتر

به کار بردن و-یا بسط پارامترها

‎${parameter}‎

همانند با ‎$parameter‎، یعنی، مقدارِ متغیر parameter. در برخی مضمون‌ها، فقط شکل کمتر مبهم ‎${parameter}‎ کار می‌کند.

می‌تواند برای الحاق متغیرها به رشته‌ها استفاده گردد.

your_id=${USER}-on-${HOSTNAME}
echo "$your_id"
#
echo "Old \$PATH = $PATH"
PATH=${PATH}:/opt/bin  # افزودن ‎/opt/bin‎ به ‎$PATH‎ در طول مدت اجرای اسکریپت.
echo "New \$PATH = $PATH"

‎${parameter-default}‎‏، ‎${parameter:-default}‎

اگر ‎parameter‎ برقرار نیست، ‎default‎ به کار برود.

var1=1
var2=2
# اگر ‎var3‎ برقرار نباشد (‎unset‎ باشد).

echo ${var1-$var2}   #
echo ${var3-$var2}   #
#  به پیشوند ‎$‎ توجه کنید.



echo ${username-`whoami`}
# اگر متغیر ‎$username‎ هنوز ‎unset‎ باشد، نتیجه ‎`whoami`‎ را منعکس می‌کند.

‎${parameter-default}‎ و ‎${parameter:-default}‎ تقریباً معادل هستند. کاراکتر اضافی : فقط موقعی که parameter تعریف شده، اما تهی باشد، یک تفاوت ایجاد می‌کند.

#!/bin/bash
#

#   چنانچه متغیر تعریف شده باشد، حتی اگر تهی باشد،
#+        

username0=
echo "username0 has been declared, but is set to null."
echo "username0 = ${username0-`whoami`}"
#
# مترجم: ترکیب فاقد ‎:‎ با متغیر تهی به عنوان تعریف شده رفتار می‌کند و default انتخاب نمی‌شود.

echo

echo username1 has not been declared.
echo "username1 = ${username1-`whoami`}"
# 

username2=
echo "username2 has been declared, but is set to null."
echo "username2 = ${username2:-`whoami`}"
#                            ^
# نمایش داده خواهد شد، به علت وجود ‎:-‎ به جای فقط ‎-‎ در شرط بررسی.
#                             

# مترجم: ترکیب دارای ‎:‎ با متغیر تهی به عنوان تعریف نشده رفتار می‌کند و default انتخاب می‌شود.

#

variable=
#

echo "${variable-0}"       #       
echo "${variable:-1}"      #                  
#

unset variable

echo "${variable-2}"       #
echo "${variable:-3}"      #

exit 0

ساختار پارامتر پیش‌فرض در «غیاب» شناسه‌های خط فرمان، در اسکریپت‌ها مورد استفاده پیدا می‌کند.

DEFAULT_FILENAME=generic.data
filename=${1:-$DEFAULT_FILENAME}
#
#+         
# 
# 
# 
# 
# 



#    از مثال «‎h‎anoi2.bash‎»‏ ‎:‎
DISKS=${1:-E_NOPARAM}   #
#        ‎$DISKS‎ را به پارامتر خط فرمان ‎$1‎ یا در صورتیکه
#+     آن پارامتر ‎unset‎ باشد به ‎$E_NOPARAM‎ تنظیم می‌کند.

همچنین مثال ‎3-4‎، مثال ‎31-2‎، و مثال ‎A-6‎ را ببینید.

این روش را با کاربرد یک لیست and برای فراهم کردن یک شناسه پیش‌فرض خط فرمان، مقایسه نمایید.

‎${parameter=default}‎‏ و ‎${parameter:=default}‎

در صورتیکه ‎parameter‎ برقرار نیست، مقدار آن به default تنظیم گردد.

هر دو شکل تقریباً معادل هستند. شکل : فقط در صورتیکه ‎$parameter‎ تعریف شده اما تهی باشد، یک تفاوت ایجاد می‌کند، ‎[1]‎ مانند مورد فوق.

echo ${var=abc}   #
echo ${var=xyz}   #
# ‎$var‎ از قبل به ‎abc‎ تنظیم شده بود، بنابراین تغییر نکرد.

‎${parameter+alt_value}‎‏ و ‎${parameter:+alt_value}‎

اگر ‎parameter‎ برقرار باشد، ‎alt_value‎ استفاده شود، وگرنه رشته تهی به کار برود.

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

echo "###### \${parameter+alt_value} ########"
echo

a=${param1+xyz}
echo "a = $a"      #

param2=
a=${param2+xyz}
echo "a = $a"      #

param3=123
a=${param3+xyz}
echo "a = $a"      #

echo
echo "###### \${parameter:+alt_value} ########"
echo

a=${param4:+xyz}
echo "a = $a"      #

param5=
a=${param5:+xyz}
echo "a = $a"      #
#  نتیجه‌ای متفاوت با شکل ‎a=${param5+xyz}‎

param6=123
a=${param6:+xyz}
echo "a = $a"      #

‎${parameter?err_msg}‎ و ‎${parameter:?err_msg}‎

در صورتیکه parameter برقرار باشد، استفاده شود، وگرنه err_msg چاپ شود و با یک وضعیت خروج ‎1‎ اسکریپت صرف‌نظر گردد.

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

مثال ‎10-7‎- کاربرد جایگزینی پارامتر و پیغام‌های خطا

#!/bin/bash

#
#           
#   اگر برای مثال، ‎$USER‎‏، نام شخص در console، برقرار
#+       

: ${HOSTNAME?} ${USER?} ${HOME?} ${MAIL?}
  echo
  echo "Name of the machine is $HOSTNAME."
  echo "You are $USER."
  echo "Your home directory is $HOME."
  echo "Your mail INBOX is located in $MAIL."
  echo
  echo "If you are reading this message,"
  echo "critical environmental variables have been set."
  echo
  echo

# ------------------------------------------------------

#  ساختار ‎${variablename?}‎ نیز می‌تواند داخل اسکریپت
#+   

ThisVariable=Value-of-ThisVariable
#   
#+
: ${ThisVariable?}
echo "Value of ThisVariable is $ThisVariable".

echo; echo


: ${ZZXy23AB?"ZZXy23AB has not been set."}
#      چون ‎ZZXy23AB‎ تنظیم نگردیده است، پس
#+

#
#   


#   همان نتیجه با این موارد:   ‎dummy_variable=${ZZXy23AB?}‎
#
#
#

#  این روشها را مقایسه کنید با کنترل توسط ‎"set -u"‎
#+



echo "You will not see this message, because script already terminated."

HERE=0
exit $HERE   #               

# در واقع، این اسکریپت وضعیت خروج ‎(echo $?)‎ یک را برگشت خواهد داد.

مثال ‎10-8‎- جایگزینی پارامتر و پیغام‌های «کاربرد»

#!/bin/bash
#

: ${1?"Usage: $0 ARGUMENT"}
#   
#+                        

#

echo "These two lines echo only if command-line parameter given."
echo "command-line parameter = \"$1\""

exit 0  #


#
#    اگر پارامتر خط فرمان حاضر باشد، آنوقت ‎"$?"‎ برابر ‎0‎ است.
#                 اگر حاضر نباشد، آنوقت ‎"$?"‎ برابر با ‎1‎ است.

جایگزینی و-یا بسط پارامتر. عبارت‌های زیر کامل کننده انطباق در عملیات رشته‌ای expr هستند ( مثال ‎16-9‎ را ببینید). این موارد بخصوص معمولاً در تجزیه نام مسیر فایلها استفاده می‌شوند.

طول متغیر / رشته فرعی پاک شونده

‎${#var}‎

طول رشته (تعداد کاراکترها در ‎$var‎). برای یک آرایه، ‎${#array}‎ طول عنصر اول آرایه است. مترجم: برای سایر عناصر، شاخص آن را تعیین کنید.

موارد استثناء:

  • ‎${#*}‎ و ‎${#@}‎ تعداد پارامترهای مکانی را نمایش می‌دهند.

  • برای یک آرایه، ‎${#array[*]}‎ و ‎${#array[@]}‎ تعداد عناصر در آرایه را بیان می‌کنند.

مثال ‎10-9‎- طول یک متغیر

#!/bin/bash
#
E_NO_ARGS=65

if [ $# -eq 0 ]  #
then
  echo "Please invoke this script with one or more command-line arguments."
  exit $E_NO_ARGS
fi  

var01=abcdEFGH28ij
echo "var01 = ${var01}"
echo "Length of var01 = ${#var01}"
#
var02="abcd EFGH28ij"
echo "var02 = ${var02}"
echo "Length of var02 = ${#var02}"

echo "Number of command-line arguments passed to script = ${#@}"
echo "Number of command-line arguments passed to script = ${#*}"

exit 0

‎${var#Pattern}‎‏، ‎${var##Pattern}‎

‎${var#Pattern}‎ کوتاهترین قسمت ‎$Pattern‎ را که با بخش مقدم ‎$var‎ مطابقت می‌کند، از ‎$var‎ حذف می‌کند.

‎${var##Pattern}‎ بلندترین قسمت ‎$Pattern‎ را که با بخش مقدم ‎$var‎ مطابقت نماید، از ‎$var‎ حذف می‌کند.

یک کاربرد تشریحی از مثال ‎A-7‎:

#         تابع از مثال "days-between.sh" است.
# زدودن صفر(های) مقدم از شناسه عبور داده شده.

strip_leading_zero () #       
{                     
  return=${1#0}       #        ‎"1"‎ به ‎"$1"‎ اشاره می‌کند -- شناسه عبور داده شده.
}                     #   ‎"0"‎ چیزی است که باید از ‎"$1"‎ حذف شود -- زدودن صفرها.

گونه پیچیده‌تر ‎Manfred Schwarb‎ از مثال فوق:

strip_leading_zero2 () #  زدودن صفر(های) احتمالی مقدم، چون در غیر اینصورت ‎‌Bash‎
{                      #  
  shopt -s extglob     #                       فعال کردن ‎globbing‎ توسعه یافته.
  local val=${1##+(0)} #      کاربرد متغیر محلی‎، بلندترین موردانطباق رشته‌های ‎0‎
  shopt -u extglob     #                    غیرفعال کردن ‎globbing‎ توسعه یافته.
  _strip_leading_zero2=${val:-0}
                       #      اگر ورودی صفر بود، به جای ‎""‎ صفر برگشت داده شود.
}

یک کاربرد تشریحی دیگر:

echo `basename $PWD`        # 
echo "${PWD##*/}"           # 
echo
echo `basename $0`          # 
echo $0                     # 
echo "${0##*/}"             # 
echo
filename=test.data
echo "${filename##*.}"      # 
                            # 

‎${var%Pattern}‎‏، ‎${var%%Pattern}‎

‎${var%Pattern}‎ کوتاه‌ترین قسمت ‎$Pattern‎ را که با بخش انتهایی ‎$var‎ مطابقت می‌کند از ‎$var‎ حذف می‌کند.

‎${var%%Pattern}‎ بلندترین قسمت ‎$Pattern‎ را که با بخش انتهایی ‎$var‎ مطابقت می‌کند از ‎$var‎ حذف می‌کند.

‎Bash‎ در نگارش ‎2‎ گزینه‌های اضافه‌ای را ضمیمه کرد.

مثال ‎10-10‎- انطباق الگو در جایگزینی پارامتر

#!/bin/bash
#

#        انطباق الگو با استفاده از عملگرهای جایگزینی پارامتر ‎# ## % %%‎ 

var1=abcd12345abc6789
pattern1=a*c  #  ‎*‎ (کاراکتر عام) با هر چیزی در میان ‎a - c‎ مطابقت می‌کند.

echo
echo "var1 = $var1"           #
echo "var1 = ${var1}"         #
                              #
echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"   # ‎a*c‎  (هر چیزی بین ‎'a'‎ و ‎'c'‎)
echo "--------------"
echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #
#  کوتاهترین انطباق ممکن، سه کاراکتر نخست  abcd12345abc6789 را از بین می‌برد
#                   ^^^^               |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #     
#    بلندترین انطباق ممکن، ‎12‎ کاراکتر نخست ‎abcd12345abc6789‎ را از بین می‌برد
#                         ^^^^     |----------|

echo; echo; echo

pattern2=b*9            #     هرچیزی بین ‎'b'‎ و ‎'9'‎
echo "var1 = $var1"     #  بازهم  abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2}  =' "${var1%$pattern2}"     #
# کوتاهترین مورد انطباق، ‎6‎ کاراکتر انتهایی  abcd12345abc6789 را حذف می‌کند.
#                            ^^^^^^  |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #
# بلندترین انطباق ممکن، ‎12‎ کاراکتر انتهایی  abcd12345abc6789 را حذف می‌کند.
#                                                   ^^^^^^  |-------------|

#  به خاطر داشته باشید، ‎#‎ و ‎##‎ از انتهای سمت چپ (ابتدای) رشته عمل می‌کنند،
#                                   اما ‎%‎ و ‎%%‎ از انتهای راست عمل می‌کنند.

echo

exit 0

مثال ‎10-11‎- تغییر پسوند نام فایلها :

#!/bin/bash
#
#
#
#
#                          مثال:
#    برای تغییرنام تمام فایلهای ‎*.gif‎ دایرکتوری کاری جاری به ‎*.jpg‎
#


E_BADARGS=65

case $# in
  0|1)             #     در این مضمون میله عمودی به معنی ‎"or"‎ است.
  echo "Usage: `basename $0` old_file_suffix new_file_suffix"
  exit $E_BADARGS  # اگر تعداد شناسه‌ها ‎0‎ یا ‎1‎ است، آنوقت خارج شود.
  ;;
esac


for filename in *.$1
#
do
  mv $filename ${filename%$1}$2
  #
  #+
done

exit 0

بسط متغیر / تعویض رشته فرعی

این ساختارها از ksh اقتباس گردیده‌اند.

‎${var:pos}‎

متغیر var با شروع از محل pos بسط داده می‌شود.

مترجم: در واقع به تعداد pos کاراکتر از ابتدای متغیر var را صرفنظر کرده، به باقیمانده آن بسط می‌یابد.
‎${var:pos:len}‎

بسط به حداکثر تعداد len کاراکتر از متغیر var، با شروع از محل pos. مثال ‎A-13‎ را برای یک مورد استفاده خلاق این عملگر مشاهده کنید.

‎${var/Pattern/Replacement}‎

اولین مورد انطباق Pattern داخل var با Replacement تعویض می‌گردد.

اگر Replacement ذکر نشود، آنوقت اولین مورد تطبیق Pattern با هیچ تعویض می‌شود، یعنی حذف می‌گردد.

‎${var//Pattern/Replacement}‎

تعویض سراسری. تمام موارد منطبق با Pattern در داخل var با Replacement تعویض می‌شوند.

همچون مورد فوق، اگر Replacement ذکر نگردد، آنوقت تمام Patternهای موجود با هیچ تعویض می‌گردند، یعنی حذف می‌شوند.

مثال ‎10-12‎- استفاده از انطباق الگو برای تجزیه رشته‌های دلخواه

#!/bin/bash

var1=abcd-1234-defg
echo "var1 = $var1"

t=${var1#*-*}
echo "var1 (with everything, up to and including first - stripped out) = $t"
# ‎t=${var1#*-}‎ هم درست همانطور کار می‌کند، چون ‎#‎ با کوتاهترین رشته منطبق
#+ می‌گردد، و * با هر مورد مقدم بر آن، از جمله یک رشته تهی مطابقت می‌کند.
#           (با تشکر از ‎‎Stephane Chazelas‎ برای اشاره کردن به این مورد.)

t=${var1##*-*}
echo "If var1 contains a \"-\", returns empty string...   var1 = $t"


t=${var1%*-*}
echo "var1 (with everything from the last - on stripped out) = $t"

echo

# -------------------------------------------
path_name=/home/bozo/ideas/thoughts.for.today
# -------------------------------------------
echo "path_name = $path_name"
t=${path_name##/*/}
echo "path_name, stripped of prefixes = $t"
#       در این مورد خاص دارای همان نتیجه ‎t=`basename $path_name`‎ است.
#        ‎t=${path_name%/}; t=${t##*/}‎ یک راه حل عمومی‌تر است اما بازهم
#+                                   گاهی اوقات با شکست مواجه می‌گردد.
# اگر ‎$path_name‎ به یک سطر جدید ختم شود، آنوقت ‎`basename $path_name`‎
#+          عمل نخواهد کرد، اما عبارت فوق کار می‌کند. (با تشکر از ‎S.C.‎)

t=${path_name%/*.*}
#  همان نتیجه مانندِ ‎t=`dirname $path_name`‎
echo "path_name, stripped of suffixes = $t"

# اینها در بعضی موارد از قبیل ‎"../"‎‏، ‎"/foo////"‎‏، ‎# "foo/"‎‏، ‎"/"‎ ناموفق
#  خواهند شد. حذف پسوندها، مخصوصاً وقتی نام خالص فاقد پسوند اما دارای
#+          نام مسیر است نیز موضوع را پیچیده می‌کند. (با تشکر از ‎S.C.‎)

echo

t=${path_name:11}
echo "$path_name, with first 11 chars stripped off = $t"
t=${path_name:11:5}
echo "$path_name, with first 11 chars stripped off, length 5 = $t"

echo

t=${path_name/bozo/clown}
echo "$path_name with \"bozo\" replaced  by \"clown\" = $t"
t=${path_name/today/}
echo "$path_name with \"today\" deleted = $t"
t=${path_name//o/O}
echo "$path_name with all o's capitalized = $t"
t=${path_name//o/}
echo "$path_name with all o's deleted = $t"

exit 0

‎${var/#Pattern/Replacement}‎

اگر پیشوند var با Pattern مطابقت نماید، آنوقت Replacement به جای Pattern جایگزین گردد.

‎${var/%Pattern/Replacement}‎

اگر پسوند var با Pattern منطبق شود، آنوقت Replacement به جای Pattern جایگزین بشود.

مثال ‎10-13‎- انطباق الگوها بر پیشوند یا پسوند رشته

#!/bin/bash
#
# نمونه نمایشی انطباق الگو بر پیشوند-پسوند رشته.

v0=abc1234zip1234abc    #            
echo "v0 = $v0"         #
echo

#                
v1=${v0/#abc/ABCDEF}    #
                        #
echo "v1 = $v1"         #
                        #

#                 انطباق بر پسوند (انتهای) رشته.
v2=${v0/%abc/ABCDEF}    #
                        #
echo "v2 = $v2"         #
                        #

echo

#  ----------------------------------------------------
# 
#+  
#  ----------------------------------------------------

v3=${v0/#123/000}       #
echo "v3 = $v3"         #
                        #
v4=${v0/%123/000}       #
echo "v4 = $v4"         #
                        #

exit 0			

‎${!varprefix*}‎‏، ‎${!varprefix@}‎

با نام‌ تمام متغیرهای تعریف شده قبلی که با varprefix شروع می‌شوند، منطبق می‌گردد.

# این گونه‌ای از ارجاع غیر مستقیم، اما با یک ‎*‎ یا ‎@‎ است.
#            ‎Bash‎ در نگارش ‎2.04‎ این ویژگی را اضافه کرد.

xyz23=whatever
xyz24=

a=${!xyz*}         #  به نام تمام متغیرهای تعریف شده که
#              با xyz شروع می‌شوند بسط می‌یابد.
echo "a = $a"      #
a=${!xyz@}         #
echo "a = $a"      #

echo "---"

abc23=something_else
b=${!abc*}
echo "b = $b"      #
c=${!b}            #
echo $c            #

یادداشت‌ها

[1]

اگر در یک اسکریپت غیر محاوره‌ای ‎$parameter‎ تهی باشد، اسکریپت با یک وضعیت خروج ‎127‎ (کد خطای ‎Bash‎ برای «‎command not found‎») خاتمه می‌یابد.