فصل ‎37‎-‏ Bash، نگارش‌های ‎2‎‏، ‎3‎‏، و ‎4‎

‎37.3‎- ‏Bash، نگارش ‎4‎

‎Chet Ramey‎ نگارش ‎4‎ پوسته Bash را در بیستم فوریه ‎2009‎ انتشار داد. این نگارش دارای یک تعداد ویژگی جدید قابل توجه، و همچنین اصلاح باگ‌های مهم می‌باشد.

از جمله موارد خواستنی و جالبِ:

  • آرایه‌های انجمنی. [1]

  • مثال ‎37-5‎. یک بانک اطلاعات ساده آدرس

    #!/bin/bash
    # fetch_address.sh
    
    declare -A address
    # گزینه ‎-A‎ آرایه انجمنی تعریف می‌کند.
    
    address[Charles]="414 W. 10th Ave., Baltimore, MD 21236"
    address[John]="202 E. 3rd St., New York, NY 10009"
    address[Wilma]="1854 Vermont Ave, Los Angeles, CA 90023"
    
    echo "Charles's address is ${address[Charles]}."
    # Charles's address is 414 W. 10th Ave., Baltimore, MD 21236.
    echo "Wilma's address is ${address[Wilma]}."
    # Wilma's address is 1854 Vermont Ave, Los Angeles, CA 90023.
    echo "John's address is ${address[John]}."
    # John's address is 202 E. 3rd St., New York, NY 10009.
    echo
    echo "${!address[*]}"   # شاخص‌های آرایه ...
    # Charles John Wilma

    مثال ‎37-6‎. یک بانک اطلاعات آدرس تا اندازه‌ای پیچیده‌تر

    #!/bin/bash
    # fetch_address-2.sh
    #  یک نگارش پیچیده‌تر اسکریپت ‎fetch_address.sh‎
    SUCCESS=0
    E_DB=99             # کد خطا برای فقدان مدخل.
    
    declare -A address
    #          گزینه ‎-A‎ آرایه انجمنی تعریف می‌کند.
    
    store_address ()
    {
      address[$1]="$2"
      return $?
    }
    
    fetch_address ()
    {
      if [[ -z "${address[$1]}" ]]
      then
        echo "$1's address is not in database."
        return $E_DB
      fi
    
      echo "$1's address is ${address[$1]}."
      return $?
    }
    
    store_address "Lucas Fayne" "414 W. 13th Ave., Baltimore, MD 21236"
    store_address "Arvid Boyce" "202 E. 3rd St., New York, NY 10009"
    store_address "Velma Winston" "1854 Vermont Ave, Los Angeles, CA 90023"
    #                             تمرین:
    #   فراخوان‌های ‎store_address‎ فوق را برای خواندن از یک فایل، سپس تخصیص
    #+             فیلد ‎1‎ به نام، فیلد ‎2‎ به آدرس در آرایه، بازنویسی کنید.
    # هر سطر از فایل قالبی نظیر بالا خواهد داشت. از یک حلقه ‎while-read‎ جهت
    #     خواندن از فایل، و از sed یا awk برای تجزیه فیلدها استفاده کنید.
    
    fetch_address "Lucas Fayne"
    # Lucas Fayne's address is 414 W. 13th Ave., Baltimore, MD 21236.
    fetch_address "Velma Winston"
    # Velma Winston's address is 1854 Vermont Ave, Los Angeles, CA 90023.
    fetch_address "Arvid Boyce"
    # Arvid Boyce's address is 202 E. 3rd St., New York, NY 10009.
    fetch_address "Bozo Bozeman"
    # Bozo Bozeman's address is not in database.
    
    exit $?        # در این حالت، کد خروج ‎99‎ است، چون برگشتی از تابع است.

    برای یک کاربرد جالب آرایه انجمنی، مثال ‎A-53‎ را ببینید.

    Caution

    شاخص عناصر آرایه می‌تواند شامل کاراکترهای فاصله درج شده باشد، یا حتی کاراکترهای فاصله مقدم و/یا دنباله داشته باشد. با این وجود، شاخص عناصر آرایه شامل فقط فضای سفید مجاز نیست.

    address[   ]="Blank"   # خطا!

  • موارد تکمیلی برای ساختارcase: خاتمه‌دهنده‌های ‎;;&‎ و ‎;&‎.

  • مثال ‎37-7‎. تست کردن کاراکترها

    #!/bin/bash
    
    test_char ()
    {
      case "$1" in
        [[:print:]] )  echo "$1 is a printable character.";;&       
        # پایان دهنده ‎;;&‎ به معنی ادامه با تست الگوی بعدی است.
        [[:alnum:]] )  echo "$1 is an alpha/numeric character.";;&  
        [[:alpha:]] )  echo "$1 is an alphabetic character.";;&     
        [[:lower:]] )  echo "$1 is a lowercase alphabetic character.";;&
        [[:digit:]] )  echo "$1 is an numeric character.";&         
        #        خاتمه‌دهنده ‎;&‎ جمله بعدی را اجرا می‌کند...
        %%%@@@@@    )  echo "********************************";;    
    #   ^^^^^^^^  ...حتی با یک الگوی تقلبی.
      esac
    }
    
    echo
    
    test_char 3
    # 3 is a printable character.
    # 3 is an alpha/numeric character.
    # 3 is an numeric character.
    # ********************************
    echo
    
    test_char m
    # m is a printable character.
    # m is an alpha/numeric character.
    # m is an alphabetic character.
    # m is a lowercase alphabetic character.
    echo
    
    test_char /
    # / is a printable character.
    echo
    # خاتمه‌دهنده ‎;;&‎ می‌تواند شرط‌های پیچیده ‎if/then‎ را صرفه‌جویی کند.
    #                          پایان‌دهنده ‎;&‎ کمتر مورد استفاده است.
  • فرمان داخلی جدید coproc دو پردازش موازی برای ارتباط گرفتن و اثر متقابل برهم فراهم می‌کند. به طوری که ‎Chet Ramey‎ در ‎Bash FAQ‎ ‎[2]‎‏ نگارش ‎4.01‎‎ اظهار می‌کند:

    یک کلمه رزرو شده جدید coproc وجود دارد که یک کمک پردازش را مشخص می‌کند:
    اجرای یک فرمان به طور غیر همزمان با دو لوله متصل شده به پوسته تولید کننده.
    کمک پردازش‌ها می‌توانند نام‌برده شوند. توصیف‌گرهای فایل ورودی و خروجی
    و PID کمک پردازش در متغیرهایی با نام‌های مختص کمک پردازش
    برای پوسته فراخوانی کننده در دسترس هستند.

    ‎George Dimitriu‎ شرح می‌دهد
    «...‎coproc‎ ...یک ویژگی مورد استفاده در جایگزینی پردازش Bash است،
    که اکنون در دسترس عموم قرار داده می‌شود.»
    این به معنای آن است که اکنون به جای فقط یک مکانیسم پشت پرده مورد استفاده به وسیله Bash،
    می‌تواند به طور صریح در یک اسکریپت فراخوانی بشود.

    کمک پردازش‌ها از توصیف‌گر‌های فایل استفاده می‌کنند. توصیف‌گرهای فایل وسیله ارتباط برقرار کردن پردازش‌ها و لوله‌ها را فراهم می‌کنند.

  • #!/bin/bash
    #      یک کمک پردازش با یک حلقه ‎while-read‎ ارتباط برقرار می‌کند.
    
    coproc { cat mx_data.txt; sleep 2; }
    #                         ^^^^^^^
    #   اجرای این را بدون ‎sleep 2‎ امتحان کنید و ببینید چه رخ می‌دهد.
    
    while read -u ${COPROC[0]} line    #  ‎${COPROC[0]}‎ توصیف‌گر فایل
    do                                 #+      برای کمک پردازش است.
      echo "$line" | sed -e 's/line/NOT-ORIGINAL-TEXT/'
    done
    
    kill $COPROC_PID                   # دیگر کمک پردازش نیاز نیست،
                                       #+بنابراین kill کردن PID آن.

    اما، مراقب باشید!

    #!/bin/bash
    
    echo; echo
    a=aaa
    b=bbb
    c=ccc
    
    coproc echo "one two three"
    while read -u ${COPROC[0]} a b c;  # توجه نمایید که این حلقه یک
    do                                 #+    پوسته فرعی اجرا می‌کند.
      echo "Inside while-read loop: ";
      echo "a = $a"; echo "b = $b"; echo "c = $c"
      echo "coproc file descriptor: ${COPROC[0]}"
    done 
    
    # a = one
    # b = two
    # c = three
    # تا اینجا، خوب است، اما ...
    ---------------------------------------------------------------------------#
    مترجم: اگر چندان هم خوب نیست، و توصیف‌گر فایل در آخرین دستور echo بالا نمایش #
    داده نمی‌شود، ممکن است لازم باشد سطر فرمان coproc (سطر ۸) را مانند مثال قبل  #
    به صورت ‎coproc { echo "one two three"; sleep 2; }‎ بنویسید. امتحان کنید.    #
    --------------------------------------------------------------------------# 
    echo "-----------------"
    echo "Outside while-read loop: "
    echo "a = $a"  # a =
    echo "b = $b"  # b =
    echo "c = $c"  # c =
    echo "coproc file descriptor: ${COPROC[0]}"
    echo
    #   کمک پردازش هنوز در حال اجرا است، اما ...
    #+بازهم پردازش والد قادر به ارث‌ بردن متغیرها
    #+از پردازش فرزند یعنی حلقه ‎while-read‎ نیست.
    
    #  این را با اسکریپت ‎badread.sh‎ مقایسه کنید.

    Caution

    کمک پردازش غیر همزمان است، و این ممکن است باعث مشکل بشود. ممکن است قبل از اینکه پردازش دیگر مخابره با آن را تمام کرده باشد، به پایان برسد.
    مترجم: استفاده از sleep در دو مثال فوق نیز برای پیش‌گیری از این مشکل است.

    #!/bin/bash
    
    coproc cpname { for i in {0..10}; do echo "index = $i"; done; }
    #      ^^^^^^           این یک کمک پردازش با اختصاص نام است.
    read -u ${cpname[0]}
    echo $REPLY         # index = 0
    echo ${COPROC[0]}   # بدون خروجی ... بعد از اولین تکرار حلقه
                        #+           کمک پردازش خاتمه یافته است.
    
    #              اما، ‎George Dimitriu‎ دارای یک تصحیح جزیی است.
    
    coproc cpname { for i in {0..10}; do echo "index = $i"; done; sleep 1;
    echo hi > myo; cat - >> myo; }
    #       ^^^^^                  این یک کمک پردازش با نام است.
    
    echo "I am main"$'\04' >&${cpname[1]}
    myfd=${cpname[0]}
    echo myfd=$myfd
    
    ### while read -u $myfd
    ### do
    ###   echo $REPLY;
    ### done
    
    echo $cpname_PID
    
    #  این اسکریپت را با حلقه while توضیحی شده و بدون آن اجرا کنید، و این
    #+آشکار می‌سازد که هر پردازش، پوسته جاری و کمک پردازش، منتظر می‌ماند تا
    #+   دیگری نوشتن در لوله‌ای را که خودش برای نوشتن فعال کرده، تمام کند.
    
  • فرمان داخلی جدید mapfile بدون استفاده از یک حلقه یا جایگزینی فرمان، امکان بار کردن یک آرایه با محتویات یک فایل متنی را فراهم می‌کند.

  • #!/bin/bash
    
    mapfile Arr1 < $0   #        مانند همان نتیجه ‎Arr1=( $(cat $0) )‎
    
    echo "${Arr1[@]}"   #   تمام این اسکریپت را در stdout کپی می‌کند.
    
    echo "--"; echo     
     #            اما، همانند ‎read -a‎ نیست!!!
    read -a Arr2 < $0
    echo "${Arr2[@]}"   # فقط سطر اول اسکریپت را داخل آرایه می‌خواند.
    
    exit

  • فرمان داخلی read کمی بهتر شده است. اکنون گزینه ‎-t‎ برای timeout مقادیر کسری ‎(decimal)‎ را قبول می‌کند ‎[3]‎ و گزینه ‎-i‎ بارگیری اولیه بافر ویرایش را اجازه می‌دهد. ‎[4]‎ متاسفانه، این افزایش‌ها هنوز یک کار در جریان پیشرفت هستند و (هنوز) قابل استفاده در اسکریپت‌ها نیستند.

  • جایگزینی پارامتر عملگرهای تبدیل حالت حروف دریافت می‌کند.

  • #!/bin/bash
    
    var=veryMixedUpVariable
    echo ${var}            # veryMixedUpVariable
    echo ${var^}           # VeryMixedUpVariable
    #         *              کاراکتر اول به حرف بزرگ تبدیل گردیده است.
    echo ${var^^}          # VERYMIXEDUPVARIABLE
    #         **             تمام کاراکترها به حالت بزرگ تبدیل شده‌اند.
    echo ${var,}           # veryMixedUpVariable
    #         *                 کاراکتر اول به حرف کوچک تبدیل شده است.
    echo ${var,,}          # verymixedupvariable
    #         **             تمام کاراکترها به حروف کوچک تبدیل شده‌اند.
    

  • فرمان داخلی declare اکنون گزینه ‎‎-l‎ ‏(lowercase) حالت کوچک حروف و ‎-c‎ ‏(capitalize) حروف بزرگ را می‌پذیرد.

  • #!/bin/bash
    
    declare -l var1           #           به حروف کوچک تبدیل خواهد نمود
    var1=MixedCaseVARIABLE
    echo "$var1"              #  mixedcasevariable
                              # همانند اثر ‎echo $var1 | tr A-Z a-z‎ است.
    
    declare -c var2           # فقط کاراکتر اول را به بزرگ تبدیل می‌کند.
    var2=originally_lowercase
    echo "$var2"              # Originally_lowercase
                              # همانند اثر ‎echo $var2 | tr a-z A-Z‎ نیست.

  • بسط ابرو دارای گزینه‌های بیشتری است.

    افزایش-کاهش، تعیین شده در عبارت انتهایی داخل ابروها.

  • #!/bin/bash
    
    echo {40..60..2}
    # 40 42 44 46 48 50 52 54 56 58 60
    #              تمام اعداد زوج، بین ‎40‎ و ‎60‎.
    
    echo {60..40..2}
    # 60 58 56 54 52 50 48 46 44 42 40
    # تمام اعداد زوج، بین ‎40‎ و ‎60‎، شمارش معکوس.
    #                         در واقع، یک کاهش.
    echo {60..40..-2}
    #           همان خروجی، علامت منها لازم نیست.
    
    #            اما، در مورد حروف و علایم چطور؟
    echo {X..d}
    # X Y Z [  ] ^ _ ` a b c d
    # کاراکتر \ که یک فاصله را escape می‌کند نمایش داده نمی‌شود.

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

    bash$ echo {010..15}
    010 011 012 013 014 015
    
    bash$ echo {000..10}
    000 001 002 003 004 005 006 007 008 009 010
    
  • استخراج رشته فرعی در پارامترهای مکانی اکنون با ‎$0‎ به عنوان شاخص صفر شروع می‌شود. (این یک ناهماهنگی در رفتار پارامترهای مکانی را تصحیح می‌کند.)

  • #!/bin/bash
    # show-params.bash
    # به Bash نگارش ‎4+‎ نیاز دارد.
    
    # این اسکریپت را با حد اقل یک پارامتر مکانی فراخوانی کنید.
    
    E_BADPARAMS=99
    
    if [ -z "$1" ]
    then
      echo "Usage $0 param1 ..."
      exit $E_BADPARAMS
    fi
    
    echo ${@:0}
    
    
    bash3$ show-params.bash‎ one two three
    one two three
    
    bash4$ show-params.bash one two three
    show-params.bash one two three
    #  $0             $1  $2  $3

  • عملگر جدید ** در globbing، انطباق نام فایل‌ها و دایرکتوری‌ها را به طور بازگشتی انجام می‌دهد.

  • #!/bin/bash
    # filelist.bash
    
    shopt -s globstar  #       باید globstar فعال باشد، وگرنه کار نمی‌کند.
                       #   گزینه پوسته globstar در Bash نگارش ‎4‎ جدید است.
    echo "Using *"; echo
    for filename in *
    do
      echo "$filename"
    done               #تنها فایل‌های دایرکتوری جاری ‎($PWD)‎ را لیست می‌کند.
    
    echo; echo "--------------"; echo
    
    echo "Using **"
    for filename in **
    do
      echo "$filename"
    done               #      به طور بازگشتی درخت فایل کامل را لیست می‌کند.
    
    exit
    
    #     خروجی اسکریپت
    
    Using *
    
    allmyfiles
    filelist.bash
    
    --------------
    
    Using **
    allmyfiles
    allmyfiles/file.index.txt
    allmyfiles/my_music
    allmyfiles/my_music/me-singing-60s-folksongs.ogg
    allmyfiles/my_music/me-singing-opera.ogg
    allmyfiles/my_music/piano-lesson.1.ogg
    allmyfiles/my_pictures
    allmyfiles/my_pictures/at-beach-with-Jade.png
    allmyfiles/my_pictures/picnic-with-Melissa.png
    filelist.bash

  • متغیر داخلی جدید ‎$BASHPID‎.

  • یک تابع درونی جدید مدیریت خطا به نام ‎command_not_found_handle‎ وجود دارد.

  • #!/bin/bash
    
    command_not_found_handle ()
    { # پارامترهای تلویحی را قبول می‌کند.
      echo "The following command is not valid: \""$1\"""
      echo "With the following argument(s): \""$2\"" \""$3\"""   # $4, $5 ...
    } # ‎$1‎‏، ‎$2‎‏، وغیره به صورت صریح به تابع عبور داده نمی‌شوند.
    
    bad_command arg1 arg2
    
    # The following command is not valid: "bad_command"
    # With the following argument(s): "arg1" "arg2"

‎37.3.1‎- ‏Bash، نگارش ‎4.1‎

نگارش ‎4.1‎ از Bash، منتشر شده در ‎May‎ سال ‎2010‎، اساساً یک به روزرسانی bugfix بود.

  • فرمان printf اکنون یک گزینه ‎-v‎ برای تنظیم شاخص‌های آرایه قبول می‌کند.

  • در درون براکت‌های دوگانه، عملگرهای مقایسه رشته ‎>‎ و ‎<‎ اکنون با locale(منطقه) همنوایی می‌کنند. چون تنظیم منطقه می‌تواند روی ترتیب مرتب‌سازی عبارت‌های رشته‌ای اثر کند، این دارای آثار جانبی بر روی تست‌های مقایسه درون عبارت‌های ‎[[ ... ]]‎ است.

  • فرمان داخلی read اکنون یک گزینه ‎-N‎ ‏(‎read -N chars‎) می‌پذیرد، که باعث خاتمه یافتن read بعد از تعداد chars کاراکتر می‌گردد.

  • مثال ‎37-8‎. خواندن تعداد N کاراکتر

    #!/bin/bash
    # Requires Bash version -ge 4.1 ...
    
    num_chars=61
    
    read -N $num_chars var < $0   # خواندن ‎61‎ کاراکتر نخست اسکریپت!
    echo "$var"
    exit
    
    ####### خروجی اسکریپت #######
    
    #!/bin/bash
    # Requires Bash version -ge 4.1 ...
    
    num_chars=61
    
  • ‎Here document‎های قرار داده شده در ساختارهای جایگزینی فرمان ‎$( ... )‎ می‌تواند با یک ‎)‎ ساده خاتمه یابد.

  • مثال ‎37-9‎. استفاده از یک here document برای تنظیم یک متغیر

    #!/bin/bash
    # here-commsub.sh
    # به Bash نگارش ‎4.1‎ یا بالاتر نیاز دارد ...
    
    multi_line_var=$( cat <<ENDxxx
    ------------------------------
    This is line 1 of the variable
    This is line 2 of the variable
    This is line 3 of the variable
    ------------------------------
    ENDxxx)
    
    #    به جای آنچه که ‎Bash 4.0‎ نیاز دارد:
    #+  که رشته پایان‌بخش سرحد و پرانتز بسته
    #+ خاتمه دهنده در سطرهای جداگانه باشند.
    
    # ENDxxx
    # )
    
    echo "$multi_line_var"
    
    # به هر حال بازهم Bash این هشدار را صادر می‌کند.
    # warning: here-document at line 10 delimited by end-of-file (wanted `ENDxxx')

‎37.3.2‎- ‏Bash، نگارش ‎4.2‎

نگارش ‎4.2‎ از Bash، منتشر شده در فوریه ‎2011‎، علاوه بر اصلاح باگ‌ها شامل یک تعداد ویژگی‌های جدید و افزایش‌ها است.

  • Bash اکنون از escape یونی‌کد ‎\u و ‎\U‎ پشتیبانی می‌کند.

  • echo -e '\u2630'   #    کاراکتر نوار افقی سه‌گانه.
     #           معادل دستور پر پیچ و خم‌تر پایین است:
    echo -e "\xE2\x98\xB0"
     #          قابل شناسایی توسط نگارش‌های قبلی Bash.
    
    echo -e '\u220F'   # ‎PI‎ (حرف یونانی و نماد ریاضی)
    echo -e '\u0416'   #  حرف ‎"ZHE"‎ (از حروف سیریلیک)
    echo -e '\u2708'   #   نماد هواپیما(فونت Dingbat)
    echo -e '\u2622'   #     نماد سه‌پره رادیواکتیویته
    
    echo -e "The amplifier circuit requires a 100 \u2126 pull-up resistor."
    
    unicode_var='\u2640'
    echo -e $unicode_var      #             نماد مونث
    printf "$unicode_var \n"  #نماد مونث، با سطر جدید
    
    #       و برای موردی تا اندازه‌ای استادانه‌تر . . .
    
    #   می‌توانیم نمادهای یونی‌کد را در یک آرایه انجمنی
    #+ذخیره نموده، سپس آنها را توسط نام بازیابی کنیم.
    #  برای خوانایی بهتر این کد را در یک ترمینال گنوم
    #+   یا ترمینالی با فونت بزرگ و پر رنگ اجرا کنید.
    
    declare -A symbol         #         آرایه انجمنی.
    
    symbol[script_E]='\u2130'
    symbol[script_F]='\u2131'
    symbol[script_J]='\u2110'
    symbol[script_M]='\u2133'
    symbol[Rx]='\u211E'
    symbol[TEL]='\u2121'
    symbol[FAX]='\u213B'
    symbol[care_of]='\u2105'
    symbol[account]='\u2100'
    symbol[trademark]='\u2122'
    
    echo -ne "${symbol[script_E]}   "
    echo -ne "${symbol[script_F]}   "
    echo -ne "${symbol[script_J]}   "
    echo -ne "${symbol[script_M]}   "
    echo -ne "${symbol[Rx]}   "
    echo -ne "${symbol[TEL]}   "
    echo -ne "${symbol[FAX]}   "
    echo -ne "${symbol[care_of]}   "
    echo -ne "${symbol[account]}   "
    echo -ne "${symbol[trademark]}   "
    echo


    مثال بالا از ساختار بسط رشته ‎$' ... '‎ استفاده می‌کند.

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

  • مثال ‎37-10‎. لوله‌کشی ورودی به یک فرمان read

    #!/bin/bash
    # lastpipe-option.sh
    
    line=''                     # مقدار تهی.
    echo "\$line = "$line""     #    $line =
    
    echo
    
    shopt -s lastpipe           #      خطا در Bash نگارش کمتر از ‎4.2‎
    echo "Exit status of attempting to set \"lastpipe\" option is $?"
                                #   ‎1‎ در Bash کمتر از ‎4.2‎، وگر نه ‎0.
    
    echo
    
    head -1 $0 | read line       # لوله کشی سطر اول اسکریپت به read
    #            ^^^^^^^^^   در پوسته‌فرعی نیست!!!
    
    echo "\$line = "$line""
    # ‎$line =‎        در نگارش‌های قدیمی‌تر Bash
    # ‎$line = #!/bin/bash‎   در Bash نگارش ‎4.2

    این گزینه «تعمیرهای» امکان‌پذیر برای این اسکریپت‌ها ارایه می‌کند: مثال ‎34-3‎ و مثال ‎15-8‎

  • شاخص‌های منفی آرایه شمارش معکوس از انتهای یک آرایه را مجاز می‌کنند.

  • مثال ‎37-11‎. شاخص‌های منفی آرایه

    #!/bin/bash
    # neg-array.sh
    # به Bash نگارش ‎4.2‎ یا بالاتر احتیاج دارد.
    
    array=( zero one two three four five )   # آرایه ۶ عضوی.
    #         0    1   2    3    4    5
    #        -6   -5  -4   -3   -2   -1
    
    # شاخص‌های منفی آرایه اکنون مجاز است.
    echo ${array[-1]}   # five
    echo ${array[-2]}   # four
    # ...
    echo ${array[-6]}   # zero
    # شاخص‌های منفی آرایه از آخرین عنصر+1 به عقب می‌شمارند.
    
    #   اما، نمی‌توانید قبل از ابتدای آرایه را فهرست کنید.
    echo ${array[-7]}   # array: bad array subscript
    
    # پس، این ویژگی جدید برای چه کاری خوب است؟ برای:
    echo "The last element in the array is "${array[-1]}""
    
    #      که بدون تردید اندکی قابل‌فهم‌تر از این است:
    echo "The last element in the array is "${array[${#array[*]}-1]}""
    echo
    
    # و ...
    
    index=0
    let "neg_element_count = 0 - ${#array[*]}"
                # تعداد عناصر، به یک عدد منفی تبدیل شده.
    
    while [ $index -gt $neg_element_count ]; do
      ((index--)); echo -n "${array[index]} "
    done        # عناصر آرایه را به طور برعکس لیست می‌کند.
    # ما در این آرایه درست فرمان tac را شبیه‌سازی کرده‌ایم.
    
    echo
    
    # همچنین ‎neg-offset.sh‎ را ببینید.
  • استخراج رشته فرعی از یک پارامتر طول منفی برای تعیین نقطه شروع از انتهای رشته هدف، استفاده می‌کند.

  • مثال ‎37-12‎. پارامتر منفی در ساختار استخراج رشته

    #!/bin/bash
    # ‎neg-offset.sh
    #                 Bash، نگارش ‎4.2‎ و بالاتر
    #          طول منفی در استخراج رشته فرعی.
    # مهم: برداشت از این ساختار را عوض می‌کند!
    
    stringZ=abcABC123ABCabc
    echo ${stringZ}                  # abcABC123ABCabc
    #                                  ‎0123456789.....‎  موقعیت در درون رشته
    echo ${stringZ:2:3}              #   cAB
    #             شمردن دوکاراکتر مقدم از ابتدای رشته، و استخراج ۳ کاراکتر.
    #  ${string:position:length}
    
    # تا اینجا چیز جدیدی نیست، اما اکنون ...
    
                                     # abcABC123ABCabc
    #                                  0123....6543210  موقعیت در درون رشته
    echo ${stringZ:3:-6}             #    ABC123
    #                ^
    #  تعیین شاخص ‎3‎ از ابتدا و شاخص ‎6‎ از انتهای رشته
    #+و استخراج رشته فرعی از نشانه اول تا نشانه دوم.
    #  ${string:offset-from-front:offset-from-end}
    #وقتی پارامتر length منفی باشد، به عنوان پارامتر 
    #+    تعیین نقطه انتهایی رشته فرعی به کار می‌رود.
    # همچنین ‎neg-array.sh‎ را ببینید.

یاداشت‌ها

[1]

به طور دقیق‌تر، ‎Bash 4+‎ دارای پشتیبانی محدود برای آرایه‌های انجمنی است. یک پیاده‌سازی حداقلی است، و فاقد بسیاری از امکانات چنین آرایه‌هایی در سایر زبان‌های برنامه‌نویسی می‌باشد. توجه نمایید که، به هر حال، به نظر می‌رسد آرایه‌های انجمنی در Bash به طور کارآمدتر و سریع‌تری نسبت به آرایه‌های دارای شاخص عددی عمل می‌کنند.

[2]

‎Copyright 1995-2009 by Chester Ramey‎

[3]

این فقط با لوله‌ها و برخی فایل‌های خاص دیگر کار می‌کند.

[4]

اما تنها در پیوستگی با readline، یعنی از خط فرمان.

[5]

و در حالیکه شما درگیر آن هستید، تعمیر نمودن مشکل ‎read لوله‌کشی شده انگشت‌نما را رسیدگی کنید.