Выбрать главу

for i in {0..23}; do hours[i]=0; done

# Собрать данные

for i in $(stat -c %y "$1"/* | cut -c 12-13); do

        j=${i/#0}

        ((++hours[j]))

        ((++count))

done

# Вывести данные

echo -e "Hour\tFiles\tHour\tFiles"

echo -e "----\t-----\t----\t-----"

for i in {0..11}; do

        j=$((i + 12))

        printf "%02d\t%d\t%02d\t%d\n" $i ${hours[i]} $j ${hours[j]}

done

printf "\nTotal files = %d\n" $count

Сценарий состоит из одной функции (usage) и основного тела с четырьмя разделами. В первом разделе проверяется, является ли аргумент командной строки именем каталога. Если нет, сценарий выводит сообщение с информацией о порядке использования и завершается.

Второй раздел инициализирует массив hours. Для этого каждому элементу массива присваивается значение 0. Массивы не требуют специальной инициализации перед использованием, но нашему сценарию важно, чтобы в массиве не оставалось элементов с пустыми значениями. Обратите внимание на необычный способ организации цикла. Используя подстановку в фигурных скобках ({0..23}), мы смогли без труда сгенерировать последовательность слов для команды for.

Следующий раздел осуществляет сбор данных, вызывая программу stat для каждого файла в каталоге. С помощью cut из результата извлекается двузначный час. Внутри цикла выполняется удаление ведущих нулей из поля с часом, потому что иначе командная оболочка попытается (и, в конечном счете, потерпит неудачу) интерпретировать значения с 00 по 09 как восьмеричные числа (см. табл. 34.1). Далее сценарий увеличивает на единицу значение элемента массива, соответствующего полученному часу дня. Наконец, будет увеличен счетчик (count), хранящий общее число файлов в каталоге.

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

Операции с массивами

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

Вывод содержимого всего массива

Для доступа к каждому элементу массива используются индексы * и @. Так же как и в случае с позиционными параметрами, индекс @ имеет большую практическую ценность. Например:

[me@linuxbox ~]$ animals=("a dog" "a cat" "a fish")

[me@linuxbox ~]$ for i in ${animals[*]}; do echo $i; done

a

dog

a

cat

a

fish

[me@linuxbox ~]$ for i in ${animals[@]}; do echo $i; done

a

dog

a

cat

a

fish

[me@linuxbox ~]$ for i in "${animals[*]}"; do echo $i; done

a dog a cat a fish

[me@linuxbox ~]$ for i in "${animals[@]}"; do echo $i; done

a dog

a cat

a fish

Мы создали массив animals и сохранили в нем три строки по два слова в каждой. Затем выполнили четыре цикла, чтобы посмотреть, как выполняется разбиение содержимого массива на слова. Инструкции ${animals[*]} и ${animals[@]} действуют идентично, если они не заключены в кавычки. Индекс * возвращает содержимое массива, разбитое на отдельные слова, тогда как индекс @ возвращает три «слова», соответствующие «истинному» содержимому массива.

Определение числа элементов в массиве

Определить число элементов в массиве, так же как длину строки, можно с помощью механизма подстановки параметров. Например:

[me@linuxbox ~]$ a[100]=foo

[me@linuxbox ~]$ echo ${#a[@]} # число элементов в массиве

1

[me@linuxbox ~]$ echo ${#a[100]} # длина элемента с индексом 100

3

Мы создали массив a и записали строку foo в элемент с индексом 100. Далее с помощью механизма подстановки параметров мы определили длину массива, используя при этом форму записи индекса @. Затем определили длину элемента с индексом 100, содержащего строку foo. Обратите внимание, что даже при том, что мы присвоили строку элементу с индексом 100, bash сообщает, что в массиве имеется только один элемент. Такое поведение необычно для тех языков, в которых неиспользуемые элементы массива (элементы с индексами 0–99) были бы инициализированы пустыми значениями и учитывались бы при определении размера массива.

Поиск используемых индексов

Так как bash позволяет создавать разреженные массивы путем присваивания значений отдельным элементам, иногда требуется определить, какие элементы действительно существуют. Это можно сделать с помощью механизма подстановки параметров, как показано ниже:

${!массив[*]}

${!массив[@]}

где массив — это имя переменной-массива. Как и в других случаях использования * и @ в операциях подстановки, форма @, заключенная в кавычки, оказывается наиболее полезной, так как выполняет подстановку нераздробленных значений элементов: