Advanced Bash-Scripting Guide: Искусство программирования на языке сценариев командной оболочки | ||
---|---|---|
Назад | Вперед |
Текущая версия Bash, та, которая скорее всего установлена в вашей системе, фактически -- 2.XX.Y.
bash$ echo $BASH_VERSION 2.05.8(1)-release В этой версии классического языка сценариев Bash были добавлены переменные-массивы, [1] расширение строк и подстановка параметров, улучшен метод косвенных ссылок на переменные.
Пример 34-1. Расширение строк
#!/bin/bash # "Расширение" строк (String expansion). # Введено в Bash, начиная с версии 2. # Строки вида $'xxx' # могут содержать дополнительные экранированные символы. echo $'Звонок звенит 3 раза \a \a \a' echo $'Три перевода формата \f \f \f' echo $'10 новых строк \n\n\n\n\n\n\n\n\n\n' exit 0Пример 34-2. Косвенные ссылки на переменные -- новый метод
#!/bin/bash # Косвенные ссылки на переменные. a=letter_of_alphabet letter_of_alphabet=z echo "a = $a" # Прямая ссылка. echo "Now a = ${!a}" # Косвенная ссылка. # Форма записи ${!variable} намного удобнее старой "eval var1=\$$var2" echo t=table_cell_3 table_cell_3=24 echo "t = ${!t}" # t = 24 table_cell_3=387 echo "Значение переменной t изменилось на ${!t}" # 387 # Теперь их можно использовать для ссылок на элементы массива, # или для эмуляции многомерных массивов. # Было бы здорово, если бы косвенные ссылки допускали индексацию. exit 0Пример 34-3. Простая база данных, с применением косвенных ссылок
#!/bin/bash # resistor-inventory.sh # Простая база данных, с применением косвенных ссылок. # ============================================================== # # Данные B1723_value=470 # сопротивление (Ом) B1723_powerdissip=.25 # рассеиваемая мощность (Вт) B1723_colorcode="желтый-фиолетовый-коричневый" # цветовая маркировка B1723_loc=173 # где B1723_inventory=78 # количество (шт) B1724_value=1000 B1724_powerdissip=.25 B1724_colorcode="коричневый-черный-красный" B1724_loc=24N B1724_inventory=243 B1725_value=10000 B1725_powerdissip=.25 B1725_colorcode="коричневый-черный-оранжевый" B1725_loc=24N B1725_inventory=89 # ============================================================== # echo PS3='Введите ноиер: ' echo select catalog_number in "B1723" "B1724" "B1725" do Inv=${catalog_number}_inventory Val=${catalog_number}_value Pdissip=${catalog_number}_powerdissip Loc=${catalog_number}_loc Ccode=${catalog_number}_colorcode echo echo "Номер по каталогу $catalog_number:" echo "Имеется в наличии ${!Inv} шт. [${!Val} Ом / ${!Pdissip} Вт]." echo "Находятся в лотке # ${!Loc}." echo "Цветовая маркировка: \"${!Ccode}\"." break done echo; echo # Упражнение: # ---------- # Переделайте этот сценарий так, чтобы он использовал массивы вместо косвенных ссылок. # Какой из вариантов более простой и интуитивный? # Примечание: # ---------- # Язык командной оболочки не очень удобен для написания приложений, #+ работающих с базами данных. # Для этой цели лучше использовать языки программирования, имеющие #+ развитые средства для работы со структурами данных, #+ такие как C++ или Java (может быть Perl). exit 0Пример 34-4. Массивы и другие хитрости для раздачи колоды карт в четыре руки
#!/bin/bash # На старых системах может потребоваться вставить #!/bin/bash2. # Карты: # раздача в четыре руки. UNPICKED=0 PICKED=1 DUPE_CARD=99 LOWER_LIMIT=0 UPPER_LIMIT=51 CARDS_IN_SUIT=13 CARDS=52 declare -a Deck declare -a Suits declare -a Cards # Проще и понятнее было бы, имей мы дело # с одним 3-мерным массивом. # Будем надеяться, что в будущем, поддержка многомерных массивов будет введена в Bash. initialize_Deck () { i=$LOWER_LIMIT until [ "$i" -gt $UPPER_LIMIT ] do Deck[i]=$UNPICKED # Пометить все карты в колоде "Deck", как "невыданная". let "i += 1" done echo } initialize_Suits () { Suits[0]=Т # Трефы Suits[1]=Б # Бубны Suits[2]=Ч # Червы Suits[3]=П # Пики } initialize_Cards () { Cards=(2 3 4 5 6 7 8 9 10 В Д K Т) # Альтернативный способ инициализации массива. } pick_a_card () { card_number=$RANDOM let "card_number %= $CARDS" if [ "${Deck[card_number]}" -eq $UNPICKED ] then Deck[card_number]=$PICKED return $card_number else return $DUPE_CARD fi } parse_card () { number=$1 let "suit_number = number / CARDS_IN_SUIT" suit=${Suits[suit_number]} echo -n "$suit-" let "card_no = number % CARDS_IN_SUIT" Card=${Cards[card_no]} printf %-4s $Card # Вывод по столбцам. } seed_random () # Переустановка генератора случайных чисел. { seed=`eval date +%s` let "seed %= 32766" RANDOM=$seed } deal_cards () { echo cards_picked=0 while [ "$cards_picked" -le $UPPER_LIMIT ] do pick_a_card t=$? if [ "$t" -ne $DUPE_CARD ] then parse_card $t u=$cards_picked+1 # Возврат к индексации с 1 (временно). let "u %= $CARDS_IN_SUIT" if [ "$u" -eq 0 ] # вложенный if/then. then echo echo fi # Смена руки. let "cards_picked += 1" fi done echo return 0 } # Структурное программирование: # вся логика приложения построена на вызове функций. #================ seed_random initialize_Deck initialize_Suits initialize_Cards deal_cards exit 0 #================ # Упражнение 1: # Добавьте комментарии, чтобы до конца задокументировать этот сценарий. # Упражнение 2: # Исправьте сценарий так, чтобы карты в каждой руке выводились отсортированными по масти. # Вы можете добавить и другие улучшения. # Упражнение 3: # Упростите логику сценария.
[1] |
Chet Ramey обещал ввести в Bash ассоциативные массивы (они хорошо знакомы программистам, работающим с языком Perl) в одном из следующих релизов Bash. |