Основы Bash: циклы






Одно из основных правил системного администрирования можно выразить так: если вам нужно часто делать одно и то же, напишите сценарий, и пусть он делает эту работу за вас. Если вам необходимо выполнять какое-то действие внутри сценария несколько раз, то вам стоит воспользоваться циклами. В GNU Bash вы можете создавать циклы при помощи конструкций for, while и until.


Если вы когда-нибудь интересовались программированием,то, скорее всего, вы уже знакомы с этими конструкциями. Если же вы, подобно мне, изучаете Bash, не имея за плечами опыта программирования, использование циклов может оказаться не достаточно очевидным для понимания. Начнём с определения различий между различными типами циклов, а затем перейдём к примерам.

Цикл for предназначен для повторения действий до тех пор, пока они все не будут выполнены. Представьте, например, что у вас есть каталог с изображениями, и вам необходимо преобразовать их из одного формата в другой. Вы можете использовать цикл for совместно с программой convert из пакета ImageMagick (или какой-либо другой программой), например, для того, чтобы преобразовать изображения из формата JPEG в формат PNG. Или, например, вам может понадобиться преобразовать множество звуковых файлов из MP3 в OGG Vorbis.

Цикл while используется для повторения действий пока выполняется (является истинным) какое-то условие. Цикл until работает несколько по другому: он выполняет действие до тех пор, пока не выполнится условие. Так, например, вы можете счётчик и выполнять действие до тех пор, пока его значение не достигнет 10. Рассмотрим это более подробно на примерах.

Циклы for

Начнём с цикла for. Его формат таков:

Если вы используете цикл for в скрипте, лучше отформатировать его так:

Так, например, если вам нужно сделать резервные копии всех HTML-файлов, находящихся в каталоге, вы можете использовать следующую команду:

Здесь создаётся локальная переменная $i, выполняется команда ls *html, результаты выполнения которой и будут являться данными, инициализирующими значение переменной $i при каждой итерации цикла (в нашем примере это будет список файлов, возвращаемый командой ls, по одному за каждую итерацию). Далее, выполняется команда cp, которой среди параметров передаётся переменная $i.

Кто-то может спросить, обязательно ли использовать букву «i» в качестве имени переменной? Нет. Вы можете использовать любое корректное  для Bash имя переменной. Конечно же, в сценариях лучше использовать более осмысленные имена переменных, вроде $input или $html.

Я привёл очень краткий и простой пример использования цикла for. Вместо команды, выполняющейся в блоке do,используйте echo для того, чтобы увидеть параметры, передаваемые ей. Это очень полезная практика на стадии тестирования скриптов, а также хороший способ помочь вам более подробно разобраться с работой for.

while и until

Рассмотрим теперь конструкции while и until. Также, мы немного воспользуемся условными выражениями bash. В нашем примере мы будем использовать их для того, чтобы определять, например, является ли значение переменной большим или меньшим, чем число X; существует ли файл и является ли он каталогом. Вы также можете использовать условные выражения для определения, например, доступности файла для чтения или присутствия в его правах доступа GID-бита.

Давайте попробуем сделать что-нибудь простое, например, создадим несколько пустых файлов. В жизни это вряд ли вам пригодится, но в качестве примера — самое оно.

Этот скрипт создаст 22 файла с именами от 0 до 21. Цикл будет работать до тех пор, пока значение переменной $i меньше (-lt) 22.

Теперь давайте избавимся от созданных файлов при помощи цикла until:

Здесь мы заменили while на until, а в условном выражении заменили «меньше» (-lt) на «равно» (-eq). Таким образом, наш скрипт будет работать до тех пор, пока значение $i не достигнет 22. И вместо touch мы использовали rm, чтобы удалять файлы, а не создавать их. Просто, не так ли?




Основы Bash: циклы: 7 комментариев

  1. >for i in $( ls *html ); do cp $i $i.bak; done

    пробелы в именах файлов не будут обработаны корректно.

  2. а вот так — будут

    for i in ls *html; do cp $i $i.bak; done

    не надо сабшеллы порождать без необходимости

  3. Зачем лишние вызовы программ (ls)? Так должно быть:

    for i in *.html; do cp $i $i.bak; done

  4. >sergio_nsk пишет:

    >2010-11-23 в 6:44

    >

    >Зачем лишние вызовы программ (ls)? Так должно >быть:

    >

    >for i in *.html; do cp $i $i.bak; done

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

    for i in a\ long\,\ stupid\ folder\ name\,\ containing\ spaces/*.html; do cp «${i}» "${i}.bak; done

    в противном случае имена файлов, содержащие пробелы, не будут обработаны корректно.

  5. Ну раз это баш, то почему не

    let i++? или ((i += 1)) ? (писать меньше, нагляднее)

    [[ ? (без сабшелов, плюшки вроде ненужного «закавычивания»)

    ну и где же «закавычивание»?

    статья не по мотивам, а перевод.

    Итого: херотень.

Комментарии запрещены.