Bash.Основы BASH.Часть 2. — различия между версиями
Админ (обсуждение | вклад) м |
Админ (обсуждение | вклад) м (→Циклы. Цикл while.) |
||
(не показана 1 промежуточная версия этого же участника) | |||
Строка 15: | Строка 15: | ||
#!/bin/bash | #!/bin/bash | ||
for i in 0 1 2 3 4 #переменной $i будем поочередно присваивать значения от 0 до 4 включительно | 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" | + | do echo "Console number is $i" >> /dev/pts/$i #Пишем в файл /dev/pts/$i (файл виртуального терминала) строку "Console number is $i" |
done #цикл окончен | done #цикл окончен | ||
exit 0 | exit 0 | ||
Строка 39: | Строка 39: | ||
echo "Do you wish to continue?" | echo "Do you wish to continue?" | ||
read again | read again | ||
− | done echo " | + | done echo "Пока" |
А теперь результат работы скрипта: | А теперь результат работы скрипта: | ||
ite@ite-desktop:~$ ./bash2_primer1.sh | ite@ite-desktop:~$ ./bash2_primer1.sh | ||
− | Please enter a name: ite The name you entered is ite Do you wish to continue? | + | 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 | ||
+ | Пока | ||
− | Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле.Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл. | + | Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле. Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл. |
+ | |||
Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор "[" аналог команды test, которая проверяет истинность условия, которое ей передали. | Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор "[" аналог команды test, которая проверяет истинность условия, которое ей передали. | ||
− | Рассмотрим еще один пример, я взял его из книги Advanced Bash Scripting. Уж очень он мне понравился :), но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO. | + | == Циклы. Цикл UNTIL-DO == |
+ | |||
+ | Рассмотрим еще один пример, я взял его из книги Advanced Bash Scripting. Уж очень он мне понравился :), но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO. Это практически полный аналог цикла WHILE-DO, только выполняется пока какое-то выражение ложно. | ||
Вот пример: | Вот пример: | ||
Строка 59: | Строка 67: | ||
echo "Введите знаменатель: " | echo "Введите знаменатель: " | ||
read divisor dnd=$dividend #мы будем изменять переменные dividend и divisor, | read divisor dnd=$dividend #мы будем изменять переменные dividend и divisor, | ||
− | #сохраним их знания в других переменных, т.к. они нам | + | #сохраним их знания в других переменных, т.к. они нам понадобятся |
− | |||
dvs=$divisor | dvs=$divisor | ||
remainder=1 | remainder=1 | ||
− | until [ "$remainder" -eq 0 ] do let "remainder = dividend % divisor" dividend=$divisor divisor=$remainder | + | until [ "$remainder" -eq 0 ] |
+ | do let "remainder = dividend % divisor" | ||
+ | dividend=$divisor | ||
+ | divisor=$remainder | ||
done echo "НОД чисел $dnd и $dvs = $dividend" | done echo "НОД чисел $dnd и $dvs = $dividend" | ||
Результат выполнения скрипта: | Результат выполнения скрипта: | ||
− | ite@ite-desktop:~$ ./bash2_primer3.sh Введите числитель: 100 Введите знаменатель: 90 НОД чисел 100 и 90 = 10 | + | ite@ite-desktop:~$ ./bash2_primer3.sh |
+ | Введите числитель: 100 | ||
+ | Введите знаменатель: 90 | ||
+ | НОД чисел 100 и 90 = 10 | ||
+ | |||
+ | == Математические операции == | ||
− | + | === Команда let.=== | |
− | |||
Команда 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 " | + | |
+ | #!/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 | + | |
+ | ite@ite-desktop:~$ ./bash2_primer2.sh | ||
+ | Введите a: 123 | ||
+ | Введите b: 12 | ||
+ | a+b= 135 | ||
+ | a/b= 10 | ||
+ | c после сдвига на 2 разряда: 40 | ||
+ | 123 / 12. остаток: 3 | ||
Ну вот, как видите ничего сложного, список математических операций стандартный: | Ну вот, как видите ничего сложного, список математических операций стандартный: | ||
+ | |||
+ — сложение | + — сложение | ||
+ | |||
— — вычитание | — — вычитание | ||
+ | |||
* — умножение | * — умножение | ||
+ | |||
/ — деление | / — деление | ||
+ | |||
** — возведение в степень | ** — возведение в степень | ||
+ | |||
% — модуль(деление по модулю), остаток от деления | % — модуль(деление по модулю), остаток от деления | ||
− | let позволяет использовать сокращения арифметических команд, тем самым сокращая | + | |
− | Работа с внешними программами при написании shell-скриптов | + | let позволяет использовать сокращения арифметических команд, тем самым сокращая количество используемых переменных. Например: a = a+b эквивалентно a +=b и т.д |
+ | |||
+ | == Работа с внешними программами при написании shell-скриптов == | ||
Для начала немного полезной теории. | Для начала немного полезной теории. | ||
− | |||
− | В bash(как и многих других оболочках) есть встроенные файловые дескрипторы: 0 (stdin), 1 (stdout), 2 (stderr). | + | === Перенаправление потоков === |
+ | |||
+ | В bash (как и многих других оболочках) есть встроенные [[файловые дескрипторы]]: 0 (stdin), 1 (stdout), 2 (stderr). | ||
+ | |||
stdout — Стандартный вывод. Сюда попадает все что выводят программы | stdout — Стандартный вывод. Сюда попадает все что выводят программы | ||
+ | |||
stdin — Стандартный ввод. Это все что набирает юзер в консоли | stdin — Стандартный ввод. Это все что набирает юзер в консоли | ||
+ | |||
stderr — Стандартный вывод ошибок. | stderr — Стандартный вывод ошибок. | ||
− | Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), < (перенаправление ввода). Оперировать ими не сложно. Например: | + | |
− | cat /dev/random > /dev/null | + | Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), < (перенаправление ввода). Оперировать ими не сложно. |
+ | |||
+ | Например: | ||
+ | |||
+ | cat /dev/random > /dev/null | ||
+ | |||
перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция :)) ) или | перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция :)) ) или | ||
− | ls -la > listing | + | |
+ | ls -la > listing | ||
+ | |||
записать в файл listing содержание текущего каталога (уже полезней) | записать в файл listing содержание текущего каталога (уже полезней) | ||
− | Если есть необходимость дописывать в файл(при использовании ">" он | + | |
− | sudo < my_password | + | Если есть необходимость дописывать в файл(при использовании ">" он заменяется), необходимо вместо ">" использовать ">>" |
+ | |||
+ | sudo < my_password | ||
+ | |||
после просьбы sudo ввести пароль, он возьмется из файла my_password, как будто вы его ввели с клавиатуры. | после просьбы sudo ввести пароль, он возьмется из файла my_password, как будто вы его ввели с клавиатуры. | ||
+ | |||
Если необходимо записать в файл только ошибки, которые могли возникнуть при работе программы, то можно использовать: | Если необходимо записать в файл только ошибки, которые могли возникнуть при работе программы, то можно использовать: | ||
− | ./program_with_error 2> error_file | + | |
+ | ./program_with_error 2> error_file | ||
+ | |||
цифра 2 перед ">" означает что нужно перенаправлять все что попадет в дескриптор 2(stderr). | цифра 2 перед ">" означает что нужно перенаправлять все что попадет в дескриптор 2(stderr). | ||
+ | |||
Если необходимо заставить stderr писать в stdout, то это можно можно след. образом: | Если необходимо заставить stderr писать в stdout, то это можно можно след. образом: | ||
− | |||
− | |||
− | |||
− | 2.Конвееры. | + | ./program_with_error 2>&1 |
+ | |||
+ | символ "&" означает указатель на дескриптор 1 (stdout) | ||
+ | |||
+ | (По умолчанию stderr пишет на ту консоль, в которой работает пользователь (вернее пишет на дисплей)). | ||
+ | |||
+ | == 2. Конвееры. == | ||
Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой: | Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой: | ||
− | + | ||
+ | команда 1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2 | ||
+ | |||
Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например: | Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например: | ||
− | |||
− | |||
− | Чаще всего скрипты на Bash используются в качестве автоматизации каких-то рутинных операций в консоли, отсюда иногда возникает необходимость в обработке stdout одной команды и передача на stdin другой команде, при этом результат выполнения одной команды должен быть неким образом обработан. В этом разделе я | + | 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/ помещенных в одну строку (для того чтобы её стравить циклу). | ||
+ | Как видно, все не сложно, достаточно понять принцип и написать пару своих скриптов. | ||
+ | Следующая статья возможно будет посещена использованию таких программ как sed, awk. (Продолжения нет :-( ) | ||
== См. также == | == См. также == |
Текущая версия на 21:34, 27 января 2016
Основы 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 "Пока"
А теперь результат работы скрипта:
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 Пока
Как видим цикл выполняется до тех пор, пока мы не введем что-то отличное от «yes». Между do и done можно описывать любые структуры, операторы и т.п., все они будут выполнятся в цикле. Но следует быть осторожным с этим циклом, если вы запустите на выполнение в нём какую-либо команду, без изменения переменной выражения, вы можете попасть в бесконечный цикл.
Теперь об условии истинности. После while, как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор "[" аналог команды test, которая проверяет истинность условия, которое ей передали.
Циклы. Цикл UNTIL-DO
Рассмотрим еще один пример, я взял его из книги 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
перенаправить вывод команды cat /dev/random в /dev/null (абсолютно бесполезная операция :)) ) или
ls -la > listing
записать в файл listing содержание текущего каталога (уже полезней)
Если есть необходимость дописывать в файл(при использовании ">" он заменяется), необходимо вместо ">" использовать ">>"
sudo < my_password
после просьбы sudo ввести пароль, он возьмется из файла my_password, как будто вы его ввели с клавиатуры.
Если необходимо записать в файл только ошибки, которые могли возникнуть при работе программы, то можно использовать:
./program_with_error 2> error_file
цифра 2 перед ">" означает что нужно перенаправлять все что попадет в дескриптор 2(stderr).
Если необходимо заставить stderr писать в stdout, то это можно можно след. образом:
./program_with_error 2>&1
символ "&" означает указатель на дескриптор 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/ помещенных в одну строку (для того чтобы её стравить циклу).
Как видно, все не сложно, достаточно понять принцип и написать пару своих скриптов.
Следующая статья возможно будет посещена использованию таких программ как sed, awk. (Продолжения нет :-( )