Все, что нужно знать о циклах Bash For в Linux
Программирование

Все, что нужно знать о циклах Bash For в Linux

Bash – это мощный инструмент написания сценариев и основа систем Linux. Здесь вы узнаете некоторые основные сведения

Bash-скрипты являются высокоэффективным средством автоматизации задач, особенно тех, которые используют преимущества других существующих программ. Такая автоматизация часто требует повторения аналогичной операции несколько раз, и именно здесь на помощь приходит for loop

Системные администраторы Linux и Mac обычно знакомы с созданием сценариев через терминал, но даже пользователи Windows могут принять участие в работе с помощью подсистемы Windows для Linux

Как работают сценарии Bash

Сценарий bash – это обычный текстовый файл, содержащий ряд команд, которые оболочка bash может прочитать и выполнить.Bash является оболочкой по умолчанию в macOS до Catalina и в большинстве дистрибутивов Linux

Если вы никогда раньше не работали с shell-сценариями, вам следует начать с самого простого случая. Это позволит вам отработать ключевые понятия, включая создание сценария и его выполнение

Сначала создайте следующий файл в удобном месте (в идеале сначала откройте терминал и перейдите в нужную директорию):

#!/bin/bash
echo'Hello, World'

Первая строка сообщает программе, которая ее выполняет, как ее запускать (т.е.с помощью интерпретатора bash). Вторая – это просто команда, как и любая другая, которую вы можете ввести в командной строке. Сохраните этот файл как hello_world.sh , затем:

$ chmod +x hello_world.sh
$./hello_world.sh

Команда chmod в первой строке делает файл исполняемым, что означает, что его можно запустить, набрав его имя, как во второй строке

Если в терминале вы видите, что в строке появились слова ‘Hello, World’, значит, все работает так, как нужно

Как работают циклы For

В общем программировании существует два основных типа цикла for: numeric и foreach. Числовой тип традиционно является наиболее распространенным, но в bash обычно используется наоборот

Числовые циклы for обычно ориентируются на одно целое число, которое определяет, сколько итераций будет выполнено, например:

for(i = 0; i < 100; i++) {
    /* statements to execute repeatedly */

Это хорошо знакомый цикл for, который будет повторяться ровно 100 раз, пока i не изменится внутри цикла, или другой оператор не приведет к остановке выполнения цикла for

Циклы Foreach, напротив, обычно работают со структурами, такими как списки или массивы, и выполняют итерации для каждого элемента в этой коллекции:

people =  'Peter''Paul''Mary'

foreach (people as person) {
    if(person =='Paul') {
        
    }

В некоторых языках используется немного другой синтаксис, который меняет порядок следования коллекции и элемента:

people =  'Peter''Paul''Mary'

for(personinpeople) {
    if(person =='Paul') {
        
    }

For in Loops

В bash более распространен цикл foreach или for in -loop. Основной синтаксис прост:

forargin list 
do
    /* statements to execute repeatedly */
    /* the value of arg can be obtained using$arg*/
done

Например, для итерации по трем файлам с явными именами:

forfileinone.c two.c three.c
do
    ls$file
done

Если такие файлы существуют в текущей директории, то результатом работы этого скрипта будет:

one.c
two.c
three.c

Вместо фиксированного набора файлов список можно получить с помощью шаблона glob (включающего подстановочные знаки – специальные символы, обозначающие другие символы). В следующем примере цикл for перебирает все файлы (в текущем каталоге), имена которых заканчиваются на ‘.xml’:

forfilein*.xml
do
    ls -l$file
done

Вот несколько примеров вывода:

$ -rw-r--r-- 1 bobby staff 2436 3 Nov 2019 feed.xml
$ -rw-r--r-- 1 bobby staff 6447 27 Oct 16:24 sitemap.xml

Это может выглядеть очень длинным способом:

$ ls -l *.xml

Но есть существенная разница: цикл for выполняет программу ls 2 раза, каждый раз передавая ей одно имя файла. В отдельном примере ls шаблон glob (*.xml) сначала сопоставляет имена файлов, а затем отправляет их все, как отдельные параметры командной строки, одному экземпляру ls

Вот пример, в котором используется программа wc (word count), чтобы сделать разницу более очевидной:

$ wc -l *.xml
44 feed.xml
231 sitemap.xml
275 total

Программа wc подсчитывает количество строк в каждом файле отдельно, а затем выводит общий подсчет по всем файлам. В отличие от этого, если wc работает в цикле for:

forfilein*.xml
do
    wc -l$file
done

Вы по-прежнему будете видеть счетчик для каждого файла:

44 feed.xml
231 sitemap.xml

Но общего суммарного итога нет, потому что wc выполняется изолированно, при каждой итерации цикла

Когда список не является списком

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

forfileinone.c two.c

Не так:

forfilein'one.c two.c'

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

FILES='one.c two.c'
forfilein$FILES
do
    
done

Обратите внимание, что само объявление переменной должно заключать свое значение в двойные кавычки!

Для без списка

Поскольку перебирать нечего, цикл for работает на тех аргументах командной строки, которые были предоставлены скрипту при вызове. Например, если у вас есть сценарий с именем args.sh , содержащий следующее:

#!/bin/sh
for
do
    echo$a
done

Затем выполнение args.sh даст следующее:

$./args.sh one two three
one
two
three

Bash распознает этот случай и рассматривает for a do как эквивалент for a in $@ do , где $@ – специальная переменная, представляющая аргументы командной строки

Эмуляция традиционного числового цикла For

Сценарии Bash часто имеют дело со списками файлов или строками вывода других команд, поэтому цикл типа for in является обычным. Однако традиционная операция в стиле c все еще поддерживается:

for(( i=1; i<=5; i++ ))
do
    echo$i
done

Это классическая форма с тремя частями, в которой:

  1. переменная инициализируется (i=1) при первом появлении цикла.
  2. цикл продолжается до тех пор, пока условие (i<=5) истинно.
  3. при каждом прохождении цикла переменная увеличивается (i++).

Итерация между двумя значениями – достаточно частое требование, поэтому существует более короткая и чуть менее запутанная альтернатива:

forin{1. 5}
do
    echo$i
done

Расширение скобок, которое имеет место, эффективно преобразует вышеприведенный цикл for в:

forin1 2 3 4

Более тонкое управление контуром с помощью прерывания и продолжения

Более сложные циклы for часто нуждаются в способе досрочного выхода или немедленного перезапуска основного цикла со следующим по очереди значением. Для этого bash заимствует операторы break и continue, распространенные в других языках программирования. Вот пример, который использует оба этих оператора для поиска первого файла длиной более 100 символов:

#!/bin/bash
forfilein
do
    if  ! -f$file
    then
        echo$fileis not a file'
        continue
    fi

    num_chars=$(wc -c <$file
    echo$fileis$num_charscharacters long'

    if$num_chars-gt 100  
    then
        echo'Found$file
        break
    fi
done

Цикл for здесь работает со всеми файлами в текущем каталоге. Если файл не является обычным файлом (напр.если это каталог), оператор continue используется для перезапуска цикла со следующим по очереди файлом. Если это обычный файл, второй условный блок определит, содержит ли он более 100 символов. Если да, то оператор break используется для немедленного выхода из цикла for (и достижения конца сценария)

Заключение

Сценарий bash – это файл, содержащий набор инструкций, которые могут быть выполнены. Цикл for позволяет повторять часть сценария много раз. С помощью переменных, внешних команд, а также операторов break и continue сценарии bash могут применять более сложную логику и выполнять широкий спектр задач

Теги

Об авторе

Алексей Белоусов

Привет, меня зовут Филипп. Я фрилансер энтузиаст . В свободное время занимаюсь переводом статей и пишу о потребительских технологиях для широкого круга изданий , не переставая питать большую страсть ко всему мобильному =)

Комментировать

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