Пожалуй, самый простой пример цикла for в bash-скриптах — это перебор списка простых значений:
#!/bin/bash
for var in first second third fourth fifth
do
echo The $var item
done
Ниже показаны результаты работы этого скрипта. Хорошо видно, что в переменную $var последовательно попадают элементы из списка. Происходит так до тех пор, пока цикл не дойдёт до последнего из них.
Обратите внимание на то, что переменная $var сохраняет значение при выходе из цикла, её содержимое можно менять, в целом, работать с ней можно как с любой другой переменной.
В списке, использованном при инициализации цикла for, могут содержаться не только простые строки, состоящие из одного слова, но и целые фразы, в которые входят несколько слов и знаков препинания. Например, всё это может выглядеть так:
#!/bin/bash
for var in first "the second" "the third" "I’ll do it"
do
echo "This is: $var"
done
Вот что получится после того, как этот цикл пройдётся по списку. Как видите, результат вполне ожидаем.
Ещё один способ инициализации цикла for заключается в передаче ему списка, который является результатом работы некоей команды. Тут используется подстановка команд для их исполнения и получения результатов их работы.
#!/bin/bash
file="myfile"
for var in $(cat $file)
do
echo " $var"
done
В этом примере задействована команда cat, которая читает содержимое файла. Полученный список значений передаётся в цикл и выводится на экран. Обратите внимание на то, что в файле, к которому мы обращаемся, содержится список слов, разделённых знаками перевода строки, пробелы при этом не используются.
Тут надо учесть, что подобный подход, если ожидается построчная обработка данных, не сработает для файла более сложной структуры, в строках которого может содержаться по несколько слов, разделённых пробелами. Цикл будет обрабатывать отдельные слова, а не строки. Что, если это совсем не то, что нужно?
Причина вышеописанной особенности заключается в специальной переменной окружения, которая называется IFS (Internal Field Separator) и позволяет указывать разделители полей. По умолчанию оболочка bash считает разделителями полей следующие символы:
• Пробел
• Знак табуляции
• Знак перевода строки
Если bash встречает в данных любой из этих символов, он считает, что перед ним — следующее самостоятельное значение списка.
Для того, чтобы решить проблему, можно временно изменить переменную среды IFS. Вот как это сделать в bash-скрипте, если исходить из предположения, что в качестве разделителя полей нужен только перевод строки:
IFS=$'\n'
После добавления этой команды в bash-скрипт, он будет работать как надо, игнорируя пробелы и знаки табуляции, считая разделителями полей лишь символы перевода строки.
#!/bin/bash
file="/etc/passwd"
IFS=$'\n'
for var in $(cat $file)
do
echo " $var"
done
Если этот скрипт запустить, он выведет он именно то, что от него требуется, давая, в каждой итерации цикла, доступ к очередной строке, записанной в файл.
Разделителями могут быть и другие символы. Например, выше мы выводили на экран содержимое файла /etc/passwd. Данные о пользователях в строках разделены с помощью двоеточий. Если в цикле нужно обрабатывать подобные строки, IFS можно настроить так:
IFS=:
Один из самых распространённых вариантов использования циклов for в bash-скриптах заключается в обходе файлов, находящихся в некоей директории, и в обработке этих файлов.
Например, вот как можно вывести список файлов и папок:
#!/bin/bash
for file in /home/likegeeks/*
do
if [ -d "$file" ]
then
echo "$file is a directory"
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
Если вы разобрались с предыдущим материалом из этой серии статей, вам должно быть понятно устройство конструкции if-then, а так же то, как отличить файл от папки. Если вам сложно понять вышеприведённый код, перечитайте этот материал.
Вот что выведет скрипт.
Обратите внимание на то, как мы инициализируем цикл, а именно — на подстановочный знак «*» в конце адреса папки. Этот символ можно воспринимать как шаблон, означающий: «все файлы с любыми именами». он позволяет организовать автоматическую подстановку имён файлов, которые соответствуют шаблону.
При проверке условия в операторе if, мы заключаем имя переменной в кавычки. Сделано это потому что имя файла или папки может содержать пробелы.