Войти
Android, Windows, Apple, Ликбез. Социальные сети. Драйверы
  • Японские телефоны Новый японский смартфон
  • Lenovo G500S: характеристики, основные особенности
  • Определяем серию продукта видеокарт Nvidia Характеристики карты nvidia 9800 gt
  • А конкуренты у смартфона есть
  • Что такое расширение файла TRZ?
  • Не работает динамик в "айфоне"
  • Bash цикл for от 0 до 100. Основы Bash: циклы

    Bash цикл for от 0 до 100. Основы Bash: циклы

    Краткое описание разницы в типах циклов:

    for — будет выполнять действие до тех пор, пока есть объекты для выполнения (например — чтение потока из stdin , файла или функции);
    while — выполняет действие до тех пор, пока условие является истинным;
    until — будет выполняться до тех пор, пока условие не станет истинным, т.е. пока оно false .

    Цикл FOR

    Рассмотрим такой вариант скрипта с циклом:

    $ cat loop.sh #!/bin/bash for variable in `ls -1` do echo "$variable" done

    Синтаксис очень простой и достаточно наглядно показан в примере:

    for (запускаем цикл) variable (объявляем переменную, над которой будем выполнять действия) in (направляем циклу поток) `ls -1` (команда, которую необходимо выполнить и передать в переменную $variable). Do и done — «тело» цикла, в рамках которых будут выполняться основные действия над полученными данными, а echo "$variable" — непосредственно само действие, выполняемое циклом.

    Теперь немного изменим пример, и вместо явного указания команды — применим вторую переменную:

    $ cat loop.sh #!/bin/bash ls=`ls -1` for variable in $ls do echo "$variable" done

    Теперь команда ls -1 передаётся в отдельной переменной, что позволяет более гибко работать с циклом. Вместо переменной в цикле можно использовать и функцию:

    $ cat loop.sh #!/bin/bash lsl () { ls -1 } for variable in `lsl` do echo "$variable" done

    Основное условие цикла for — он будет выполняться до тех пор, пока в переданной ему команде есть объекты для действия. Исходя из примера выше — пока в листинге ls -1 есть файлы для отображения — цикл будет передавать их в переменную и выполнять «тело цикла». Как только список файлов в директории закончится — цикл завершит своё выполнение.

    Давайте немного усложним пример.

    В каталоге имеется список файлов:

    $ ls -1 file1 file2 file3 file4 file5 loop.sh nofile1 nofile2 nofile3 nofile4 nofile5

    Нам необходимо выбрать из них только те, которые в названии не имеют слова «no «:

    $ cat loop.sh #!/bin/bash lsl=`ls -1` for variable in $lsl do echo "$variable" | grep -v "no" done $ ./loop.sh file1 file2 file3 file4 file5 loop.sh

    В цикле так же можно использовать условные выражения (conditional expressions ) […] для проверки условий и оператор break для прерывания цикла в случае срабатывания условия.

    Рассмотрим такой пример:

    $ cat loop.sh #!/bin/bash lsl=`ls -1` for variable in $lsl do if [ $variable != "loop.sh" ] then echo "$variable" | grep -v "no" else break fi done

    Цикл будет выполняться до тех пор, пока не будет встречен файл loop.sh . Как только выполнение цикла дойдёт до этого файла — цикл будет прерван командой break:

    $ ./loop.sh file1 file2 file3 file4 file5

    Ещё один пример — использование арифметических операций непосредственно перед выполнением тела цикла:

    $ cat loop.sh #!/bin/bash for ((count=1; count<11; count++)) do echo "$count" done

    Тут мы задаём три управляющих команды — count=1 , контролирующее условие — пока count меньше 11, и команду для выполнения — count +1:

    Циклы WHILE и UNTIL

    Простой пример, хорошо демонстрирующий принцип работы цикла while:

    $ cat loop.sh #!/bin/bash count=0 while [ $count -lt 10 ] do ((count++)) echo $count done

    Мы задаём переменную $count равной нулю, после чего запускаем цикл whi le с условием «пока $count меньше десяти — выполнять цикл». В теле цикла мы выполняем постфиксный инкремент +1 к переменной $count и результат выводим в stdout .

    Результат выполнения:

    $ ./loop.sh 1 2 3 4 5 6 7 8 9 10

    Как только значение переменной $count стало 10 — цикл прекратился.

    Хороший пример «бесконечного» цикла, который демонстрирует работу while:

    $ cat loop.sh #!/bin/bash count=10 while [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

    Аналогично, но «в обратную сторону» работает и цикл until:

    $ cat loop.sh #!/bin/bash count=0 until [ $count -gt 10 ] do ((count++)) echo $count done

    Тут мы задаём похожее условие, но вместо «пока переменная меньше 10» — указываем «пока переменная не станет больше чем 10». Результат выполнения:

    $ ./loop.sh 1 2 3 4 5 6 7 8 9 10 11

    Если же приведённый выше пример «бесконечного цикла» выполнить с использованием until — о не выведет ничего, в отличии от while:

    $ cat loop.sh #!/bin/bash count=10 until [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh $

    Так как «условие » изначально «истинно » — тело цикла выполняться не будет.

    Как и в цикле for — в while и until можно использовать функции. Для примера — цикл из реально использующегося скрипта, выполняющий проверку статуса сервера Tomcat (PID берётся в системе SLES , в других системах может отличаться), немного упрощенный вариант:

    $ cat loop.sh #!/bin/bash check_tomcat_status () { RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "{print $2}"` } while check_tomcat_status do if [ -n "$RUN" ] then printf "WARNING: Tomcat still running with PID $RUN." else printf "Tomcat stopped, proceeding...nn" break fi done

    Результат выполнения:

    $ ./loop.sh WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435

    Полный вариант:

    Check_tomcat_status () { RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "{print $2}"` } while check_tomcat_status; do if [ -n "$RUN" ] then printf "WARNING: Tomcat still running with PID $RUN. Stop it? " answer "Stopping Tomcat..." "Proceeding installation..." && $CATALINA_HOME/bin/shutdown.sh 2&>1 /dev/null || break sleep 2 if [ -n "$RUN" ] then printf "Tomcat still running. Kill it? " answer "Killing Tomcat..." "Proceeding installation...n" && kill $RUN || break sleep 2 fi else printf "Tomcat stopped, proceeding...nn" break fi done

    Функция answer описывалась в статье , но тут используется немного улучшенный вариант:

    Answer () { while read response; do echo case $response in |) printf "$1n" return 0 break ;; |) printf "$2n" return 1 break ;; *) printf "Please, enter Y(yes) or N(no)! " esac done }

    Тут можно было использовать как while , так и until — но не цикл for, так как for сработал бы один раз (получил PID — и завершился).

    И вот настал черёд пятого топика цикла. В нём я продолжу рассматривать управляющие структуры командного интерпретатора bash. В предыдущем посте были разобраны условные операторы. Теперь настал черёд таких неотъемлемых языковых структур, как операторы цикла. Циклы, как и условия, являются теми инструментальными средствами, которые обеспечивают управление порядком исполнения команд.
    Bash поддерживает циклы типа for, while, until и select. Теперь перейдём к подробному рассмотрению каждого из них.

    Оператор цикла for

    Общий синтаксис оператора for:

    for переменная
    do
    список команд
    done

    Цикл for в bash значительно отличается от цикла for в таких языках программирования, как C или PHP. Поэтому если вы программируете на C, вам нужно будет привыкнуть к этим отличиям, чтобы не путаться.
    В результате подстановки шаблона получается список слов. При каждой итерации переменная принимает каждое последующее значение этого списка, и выполняются команды, стоящие между do и done. Итерации прекращаются по исчерпании слов в списке.
    $ for day in Mon Tue Wed Thu Fri do echo “Сегодня $day” done
    Зарезервированные слова оператора for также можно писать в одну строчку, как это было в предыдущем посте для оператора if. Для этого нужно ставить ";". Перепишем предыдущий пример с учётом данной возможности:
    $ for day in Mon Tue Wed Thu Fri; do echo “Сегодня $day”; done
    Отсутствие конструкции эквивалентно записи in $@. О параметре $@ говорилось в .

    Оператор цикла while

    Общий синтаксис оператора while:

    while список1
    do
    список2
    done

    Сперва выполняется список1. Если он завершается успешно, т. е. возвращает нулевой код, управление переходит списку2. Итерации продолжаются до тех пор, пока результат выполнения списка1 не станет ненулевым. Например:
    i=10 while [ $i –gt 0 ]; do echo $i i=$(($i-1)) done; echo "end"

    Оператор цикла until

    Общий синтаксис оператора until:

    until список1
    do
    список2
    done

    Сперва выполняется список1. Если он завершается неуспешно, то есть с ненулевым кодом возврата, управление переходит списку2. Итерации продолжаются до тех пор, пока результат выполнения списка1 не станет нулевым. Например:
    i=10 until [ $i –lt 0 ]; do echo $i i=$(($i-1)) done; echo "end"

    Оператор цикла select

    Общий синтаксис оператора select:

    select переменная
    do
    список
    done

    В результате подстановки шаблона получается список слов. К этим словам оператор добавляет порядковые номера и выводит весь набор в стандартный поток ошибок. Отсутствие конструкции эквивалентно записи in $@. После этого выводится приглашение и считывается строка из стандартного потока ввода. Если строка содержит номер, соответствующий какому-либо слову из списка, то переменная получает его в качестве значения. Если подходящего слова не было найдено, то значением переменной становится пустая строка. После этого выполняется список команд, и итерации продолжаются до тех пор, пока в строке ввода не попадётся символ конца файла или пока в списке команд не встретится break или return.
    Команды break и return служат для управления ходом выполнения цикла. Команда break прерывает исполнение цикла, в то время как return возвращает код результата (нулевой или ненулевой).
    Оператор select полезен для создания нумерованных меню. Например, в каталоге ~/temp находится 3 файла: proto.txt, file.txt и readme. Пример фрагмента скрипта, позволяющего быстро просмотреть любой из них.
    echo "Выберите файл для просмотра:" select file in ~/temp/* Quit; do if [ -f $file ]; then cat $file; else break; fi done
    Запустив данный скрипт, мы увидим на экране:
    Выберите файл для просмотра:
    1) /home/istergul/temp/file.txt
    2) /home/istergul/temp/proto.txt
    3) /home/istergul/temp/readme
    4) Quit

    В следующем топике будут рассмотрены условные подстановки параметров. Жду ваших комментариев.

    Внимание: в посте спрятана выгода!

    Циклы for

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

    For var in list do команды done

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

    Перебор простых значений

    Пожалуй, самый простой пример цикла for в bash-скриптах - это перебор списка простых значений:

    #!/bin/bash for var in first second third fourth fifth do echo The $var item done

    Ниже показаны результаты работы этого скрипта. Хорошо видно, что в переменную $var последовательно попадают элементы из списка. Происходит так до тех пор, пока цикл не дойдёт до последнего из них.



    Простой цикл for

    Обратите внимание на то, что переменная $var сохраняет значение при выходе из цикла, её содержимое можно менять, в целом, работать с ней можно как с любой другой переменной.

    Перебор сложных значений

    В списке, использованном при инициализации цикла for , могут содержаться не только простые строки, состоящие из одного слова, но и целые фразы, в которые входят несколько слов и знаков препинания. Например, всё это может выглядеть так:

    #!/bin/bash for var in first "the second" "the third" "I’ll do it" do echo "This is: $var" done

    Вот что получится после того, как этот цикл пройдётся по списку. Как видите, результат вполне ожидаем.



    Перебор сложных значений
    TNW-CUS-FMP - промо-код на 10% скидку на наши услуги, доступен для активации в течение 7 дней"

    Инициализация цикла списком, полученным из результатов работы команды

    Ещё один способ инициализации цикла 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

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



    Построчный обход содержимого файла в цикле for

    Разделителями могут быть и другие символы. Например, выше мы выводили на экран содержимое файла /etc/passwd . Данные о пользователях в строках разделены с помощью двоеточий. Если в цикле нужно обрабатывать подобные строки, 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

    Основы BASH. Часть 2.
    Извиняюсь за такую большую задержку между статьями, но сессия дает о себе знать в самый неподходящий момент:)
    Всем спасибо за замечания, критику и дополнения, которые были озвучены в комментариях к прошлой статье .
    Эта часть, как и обещал, будет посвящена циклам, математическим операциям и использованию внешних команд.
    Начнем.

    Циклы. Цикл for-in.

    Оператор for-in предназначен для поочередного обращения к значениям перечисленным в списке. Каждое значение поочередно в списке присваивается переменной.
    Синтаксис следующий:
    for переменная in список_значений
    do
    команды
    done

    Рассмотрим небольшой пример:

    #!/bin/bash
    for i in 0 1 2 3 4 #переменной $i будем поочередно присваивать значения от 0 до 4 включительно
    do
    echo "Console number is $i" >> /dev/pts/$i #Пишем в файл /dev/pts/$i(файл виртуального терминала) строку "Console number is $i"
    done #цикл окончен
    exit 0

    После выполнения примера в первых 5 виртуальных консолях(терминалах) появится строка с её номером. В переменную $i поочередно подставляются значения из списка и в цикле идет работа со значением этой переменной

    Циклы. Цикл while.

    Цикл while сложнее цикла for-in и используется для повторения команд, пока какое-то выражение истинно(код возврата = 0).
    Синтаксис оператора следующий:
    while выражение или команда возвращающая код возврата
    do
    команды
    done

    Пример работы цикла рассмотрим на следующем примере:

    #!/bin/bash
    again=yes #присваиваем значение "yes" переменной again
    while [ "$again" = "yes" ] #Будем выполнять цикл, пока $again будет равно "yes"
    do
    echo "Please enter a name:"
    read name
    echo "The name you entered is $name"

    Echo "Do you wish to continue?"
    read again
    done
    echo "Bye-Bye"


    А теперь результат работы скрипта:
    ite@ite-desktop:~$ ./bash2_primer1.sh
    Please enter a name:
    ite
    The name you entered is ite
    Do you wish to continue?
    yes
    Please enter a name:
    mihail
    The name you entered is mihail
    Do you wish to continue?
    no
    Bye-Bye

    Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле.Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл.
    Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор "[" аналог команды test, которая проверяет истинность условия, которое ей передали.

    Рассмотрим еще один пример, я взял его из книги Advanced Bash Scripting. Уж очень он мне понравился:), но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO . Эта практически полный аналог цикла WHILE-DO, только выполняется пока какое-то выражение ложно.
    Вот пример:

    #!/bin/bash
    echo "Введите числитель: "
    read dividend
    echo "Введите знаменатель: "
    read divisor

    Dnd=$dividend #мы будем изменять переменные dividend и divisor,
    #сохраним их знания в других переменных, т.к. они нам
    #понадобятся
    dvs=$divisor
    remainder=1

    Until [ "$remainder" -eq 0 ]
    do
    let "remainder = dividend % divisor"
    dividend=$divisor
    divisor=$remainder
    done

    Echo "НОД чисел $dnd и $dvs = $dividend"


    Результат выполнения скрипта:
    ite@ite-desktop:~$ ./bash2_primer3.sh
    Введите числитель:
    100
    Введите знаменатель:
    90
    НОД чисел 100 и 90 = 10

    Математические операции

    Команда let.
    Команда let производит арифметические операции над числами и переменными.
    Рассмотрим небольшой пример, в котором мы производим некоторые вычисления над введенными числами:
    #!/bin/bash
    echo "Введите a: "
    read a
    echo "Введите b: "
    read b

    Let "c = a + b" #сложение
    echo "a+b= $c"
    let "c = a / b" #деление
    echo "a/b= $c"
    let "c <<= 2" #сдвигает c на 2 разряда влево
    echo "c после сдвига на 2 разряда: $c"
    let "c = a % b" # находит остаток от деления a на b
    echo "$a / $b. остаток: $c "


    Результат выполнения:
    ite@ite-desktop:~$ ./bash2_primer2.sh
    Введите a:
    123
    Введите b:
    12
    a+b= 135
    a/b= 10
    c после сдвига на 2 разряда: 40
    123 / 12. остаток: 3

    Ну вот, как видите ничего сложного, список математических операций стандартный:
    + - сложение
    - - вычитание
    * - умножение
    / - деление
    ** - возведение в степень
    % - модуль(деление по модулю), остаток от деления
    let позволяет использовать сокращения арифметических команд, тем самым сокращая кол-во используемых переменных. Например: a = a+b эквивалентно a +=b и т.д

    Работа с внешними программами при написании shell-скриптов

    Для начала немного полезной теории.
    Перенаправление потоков.
    В bash(как и многих других оболочках) есть встроенные файловые дескрипторы: 0 (stdin), 1 (stdout), 2 (stderr).
    stdout - Стандартный вывод. Сюда попадает все что выводят программы
    stdin - Стандартный ввод. Это все что набирает юзер в консоли
    stderr - Стандартный вывод ошибок.
    Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), < (перенаправление ввода). Оперировать ими не сложно. Например:
    перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция:))) или
    записать в файл listing содержание текущего каталога (уже полезней)
    Если есть необходимость дописывать в файл(при использовании ">" он заменятеся), необходимо вместо ">" использовать ">>"
    после просьбы sudo ввести пароль, он возьмется из файла my_password, как будто вы его ввели с клавиатуры.
    Если необходимо записать в файл только ошибки, которые могли возникнуть при работе программы, то можно использовать:
    ./program_with_error 2> error_file
    цифра 2 перед ">" означает что нужно перенаправлять все что попадет в дескриптор 2(stderr).
    Если необходимо заставить stderr писать в stdout, то это можно можно след. образом:
    символ "&" означает указатель на дескриптор 1(stdout)
    (Поумолчанию stderr пишет на ту консоль, в котрой работает пользователь(вренее пишет на дисплей)).
    2.Конвееры.
    Конвеер - очень мощный инструмент для работы с консолью Bash. Синтаксис простой:
    команда1 | команда 2 - означает, что вывод команды 1 передастся на ввод команде 2
    Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:
    ls -la | grep «hash» |sort > sortilg_list
    вывод команды ls -la передается команде grep, которая отбирает все строки, в которых встретится слово hash, и передает команде сортировке sort, которая пишет результат в файл sorting_list. Все довольно понятно и просто.

    Чаще всего скрипты на Bash используются в качестве автоматизации каких-то рутинных операций в консоли, отсюда иногда возникает необходимость в обработке stdout одной команды и передача на stdin другой команде, при этом результат выполнения одной команды должен быть неким образом обработан. В этом разделе я постораюсь объяснить основные принципы работы с внешними командами внутри скрипта. Думаю что примеров я привел достаточно и можно теперь писать только основные моменты.

    1. Передача вывода в переменную.
    Для того чтобы записать в переменную вывод какой-либо команды, достаточно заключить команду в `` ковычки, например
    a = `echo "qwerty"`
    echo $a

    Результат работы: qwerty


    Однако если вы захотите записать в переменную список директорий, то необходимо, должным образом обработать результат для помещения данных в переменную. Рассмотрим небольшой, пример:
    LIST=`find /svn/ -type d 2>/dev/null| awk "{FS="/"} {print $4}"| sort|uniq | tr "\n" " "`
    for ONE_OF_LIST in $LIST
    do
    svnadmin hotcopy /svn/$ONE_OF_LIST /svn/temp4backup/$ONE_OF_LIST
    done

    Здесь мы используем цикл for-do-done для архивирование всех директорий в папке /svn/ с помощью команды svnadmin hotcopy(что в нашем случае не имеет никого значения, просто как пример). Наибольшй интерес вызывает строка: LIST=`find /svn/ -type d 2>/dev/null| awk "{FS="/"} {print $4}"| sort|uniq | tr "\n" " "` В ней переменной LIST присваивается выполнение команды find, обработанной командами awk, sort, uniq,tr(все эти команды мы рассматривать не будем, ибо это отдельная статья). В переменной LIST будут имена всех каталогов в папке /svn/ пгомещенных в одну строку(для того чтобы её стравить циклу.

    Как видно, все не сложно, достаточно понять принцип и написать пару своих скриптов. В заключении статьи хочу пожелать удачи в изучении BASH и Linux в целом. Критика, как водится приветствуется. Следующая статья возможно будет посвещена использованию таких программ как sed, awk.