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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 64 65 66 67 68 69 70 71 72 ... 96

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

1 ... 64 65 66 67 68 69 70 71 72 ... 96
На этой странице вы можете бесплатно читать книгу Искусство программирования на языке сценариев командной оболочки - Мендель Купер бесплатно.
Похожие на Искусство программирования на языке сценариев командной оболочки - Мендель Купер книги

Оставить комментарий