KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Мендель Купер - Искусство программирования на языке сценариев командной оболочки

Мендель Купер - Искусство программирования на языке сценариев командной оболочки

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Мендель Купер, "Искусство программирования на языке сценариев командной оболочки" бесплатно, без регистрации.
Перейти на страницу:

exchange()

{

# Поменять местами два элемента массива.

local temp=${Countries[$1]} # Временная переменная

Countries[$1]=${Countries[$2]}

Countries[$2]=$temp


return

}


declare -a Countries # Объявление массива,

#+ необязательно, поскольку он явно инициализируется ниже.


# Допустимо ли выполнять инициализацию массива в нескольки строках?

# ДА!


Countries=(Нидерланды Украина Заир Турция Россия Йемен Сирия

Бразилия Аргентина Никарагуа Япония Мексика Венесуэла Греция Англия

Израиль Перу Канада Оман Дания Уэльс Франция Кения

Занаду Катар Лихтенштейн Венгрия)


# "Занаду" -- это мифическое государство, где, согласно Coleridge,

#+ Kubla Khan построил величественный дворец.


clear # Очистка экрана.


echo "0: ${Countries[*]}" # Список элементов несортированного массива.


number_of_elements=${#Countries[@]}

let "comparisons = $number_of_elements - 1"


count=1 # Номер прохода.


while [ "$comparisons" -gt 0 ] # Начало внешнего цикла

do


index=0 # Сбросить индекс перед началом каждого прохода.


while [ "$index" -lt "$comparisons" ] # Начало внутреннего цикла

do

if [ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]

# Если элементы стоят не по порядку...

# Оператор > выполняет сравнение ASCII-строк

#+ внутри одиночных квадратных скобок.


# if [[ ${Countries[$index]} > ${Countries[`expr $index + 1`]} ]]

#+ дает тот же результат.

then

exchange $index `expr $index + 1` # Поменять местами.

fi

let "index += 1"

done # Конец внутреннего цикла


let "comparisons -= 1" # Поскольку самый "тяжелый" элемент уже "опустился" на дно,

#+ то на каждом последующем проходе нужно выполнять на одно сравнение меньше.


echo

echo "$count: ${Countries[@]}" # Вывести содержимое массива после каждого прохода.

echo

let "count += 1" # Увеличить счетчик проходов.


done # Конец внешнего цикла


exit 0

--

Можно ли вложить один массив в другой?

#!/bin/bash

# Вложенный массив.


# Автор: Michael Zick.


AnArray=( $(ls --inode --ignore-backups --almost-all

--directory --full-time --color=none --time=status

--sort=time -l ${PWD} ) ) # Команды и опции.


# Пробелы важны . . .


SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} )

# Массив имеет два элемента, каждый из которых, в свою очередь, является массивом.


echo "Текущий каталог и дата последнего изменения:"

echo "${SubArray[@]}"


exit 0


--

Вложенные массивы, в комбинации с косвенными ссылками, предоставляют в распоряжение программиста ряд замечательных возможностей

Пример 25-7. Вложенные массивы и косвенные ссылки

#!/bin/bash

# embedded-arrays.sh

# Вложенные массивы и косвенные ссылки.


# Автор: Dennis Leeuw.

# Используется с его разрешения.

# Дополнен автором документа.


ARRAY1=(

VAR1_1=value11

VAR1_2=value12

VAR1_3=value13

)


ARRAY2=(

VARIABLE="test"

STRING="VAR1=value1 VAR2=value2 VAR3=value3"

ARRAY21=${ARRAY1[*]}

) # Вложение массива ARRAY1 в массив ARRAY2.


function print () {

OLD_IFS="$IFS"

IFS=$'n' # Вывод каждого элемента массива

#+ в отдельной строке.

TEST1="ARRAY2[*]"

local ${!TEST1} # Посмотрите, что произойдет, если убрать эту строку.

# Косвенная ссылка.

# Позволяет получить доступ к компонентам $TEST1

#+ в этой функции.


# Посмотрим, что получилось.

echo

echo "$TEST1 = $TEST1" # Просто имя переменной.

echo; echo

echo "{$TEST1} = ${!TEST1}" # Вывод на экран содержимого переменной.

# Это то, что дает

#+ косвенная ссылка.

echo

echo "-------------------------------------------"; echo

echo


# Вывод переменной

echo "Переменная VARIABLE: $VARIABLE"


# Вывод элементов строки

IFS="$OLD_IFS"

TEST2="STRING[*]"

local ${!TEST2} # Косвенная ссылка (то же, что и выше).

echo "Элемент VAR2: $VAR2 из строки STRING"


# Вывод элемента массива

TEST2="ARRAY21[*]"

local ${!TEST2} # Косвенная ссылка.

echo "Элемент VAR1_1: $VAR1_1 из массива ARRAY21"

}


print

echo


exit 0

--

С помощью массивов, на языке командной оболочки, вполне возможно реализовать алгоритм Решета Эратосфена. Конечно же -- это очень ресурсоемкая задача. В виде сценария она будет работать мучительно долго, так что лучше всего реализовать ее на каком либо другом, компилирующем, языке программирования, таком как C.

Пример 25-8. Пример реализации алгоритма Решето Эратосфена

#!/bin/bash

# sieve.sh


# Решето Эратосфена

# Очень старый алгоритм поиска простых чисел.


# Этот сценарий выполняется во много раз медленнее

# чем аналогичная программа на C.


LOWER_LIMIT=1 # Начиная с 1.

UPPER_LIMIT=1000 # До 1000.

# (Вы можете установить верхний предел и выше... если вам есть чем себя занять.)


PRIME=1

NON_PRIME=0


declare -a Primes

# Primes[] -- массив.


initialize ()

{

# Инициализация массива.


i=$LOWER_LIMIT

until [ "$i" -gt "$UPPER_LIMIT" ]

do

Primes[i]=$PRIME

let "i += 1"

done

# Все числа в заданном диапазоне считать простыми,

# пока не доказано обратное.

}


print_primes ()

{

# Вывод индексов элементов массива Primes[], которые признаны простыми.


i=$LOWER_LIMIT


until [ "$i" -gt "$UPPER_LIMIT" ]

do


if [ "${Primes[i]}" -eq "$PRIME" ]

then

printf "%8d" $i

# 8 пробелов перед числом придают удобочитаемый табличный вывод на экран.

fi


let "i += 1"


done


}


sift () # Отсеивание составных чисел.

{


let i=$LOWER_LIMIT+1

# Нам известно, что 1 -- это простое число, поэтому начнем с 2.


until [ "$i" -gt "$UPPER_LIMIT" ]

do


if [ "${Primes[i]}" -eq "$PRIME" ]

# Не следует проверять вторично числа, которые уже признаны составными.

then


t=$i


while [ "$t" -le "$UPPER_LIMIT" ]

do

let "t += $i "

Primes[t]=$NON_PRIME

# Все числа, которые делятся на $t без остатка, пометить как составные.

done


fi


let "i += 1"

done


}


# Вызов функций.

initialize

sift

print_primes

# Это называется структурным программированием.


echo


exit 0


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

# Код, приведенный ниже, не исполняется из-за команды exit, стоящей выше.


# Улучшенная версия, предложенная Stephane Chazelas,

# работает несколько быстрее.


# Должен вызываться с аргументом командной строки, определяющем верхний предел.


UPPER_LIMIT=$1 # Из командной строки.

let SPLIT=UPPER_LIMIT/2 # Рассматривать делители только до середины диапазона.


Primes=( '' $(seq $UPPER_LIMIT) )


i=1

until (( ( i += 1 ) > SPLIT )) # Числа из верхней половины диапазона могут не рассматриваться.

do

if [[ -n $Primes[i] ]]

then

t=$i

until (( ( t += i ) > UPPER_LIMIT ))

do

Primes[t]=

done

fi

done

echo ${Primes[*]}


exit 0

Сравните этот сценарий с генератором простых чисел, не использующим массивов, Пример A-18.

--

Массивы позволяют эмулировать некоторые структуры данных, поддержка которых в Bash не предусмотрена.

Пример 25-9. Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")

#!/bin/bash

# stack.sh: Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")


# Подобно стеку процессора, этот "стек" сохраняет и возвращает данные по принципу

#+ "первый вошел -- последний вышел".


BP=100 # Базовый указатель на массив-стек.

# Дно стека -- 100-й элемент.


SP=$BP # Указатель вершины стека.

# Изначально -- стек пуст.


Data= # Содержимое вершины стека.

# Следует использовать дополнительную переменную,

#+ из-за ограничений на диапазон возвращаемых функциями значений.


declare -a stack


push() # Поместить элемент на вершину стека.

{

if [ -z "$1" ] # А вообще, есть что помещать на стек?

then

return

fi


let "SP -= 1" # Переместить указатель стека.

stack[$SP]=$1


return

}


pop() # Снять элемент с вершины стека.

{

Data= # Очистить переменную.


if [ "$SP" -eq "$BP" ] # Стек пуст?

then

return

fi # Это предохраняет от выхода SP за границу стека -- 100,


Data=${stack[$SP]}

let "SP += 1" # Переместить указатель стека.

return

}


status_report() # Вывод вспомогательной информации.

{

echo "-------------------------------------"

echo "ОТЧЕТ"

echo "Указатель стека SP = $SP"

echo "Со стека был снят элемент ""$Data"""

echo "-------------------------------------"

echo

}


# =======================================================

# А теперь позабавимся.


echo


# Попробуем вытолкнуть что-нибудь из пустого стека.

pop

status_report


echo


push garbage

pop

status_report # Втолкнуть garbage, вытолкнуть garbage.


value1=23; push $value1

value2=skidoo; push $value2

value3=FINAL; push $value3


pop # FINAL

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*