Основы 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 производит арифметические операции над числами и переменными.
Рассмотрим небольшой пример, в котором мы производим некоторые вычисления над введенными числами:
#!/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 #сдвигает 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. Передача вывода в переменную
Для того чтобы записать в переменную вывод какой-либо команды, достаточно заключить команду в « кавычки, например
Однако если вы захотите записать в переменную список директорий, то необходимо, должным образом обработать результат для помещения данных в переменную. Рассмотрим небольшой, пример:
LIST=`find /svn/ -type d 2>/dev/null| awk ' '| 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 ‘ ‘| sort|uniq | tr ‘\n’ ‘ ‘` В ней переменной LIST присваивается выполнение команды find, обработанной командами awk, sort, uniq,tr(все эти команды мы рассматривать не будем, ибо это отдельная статья). В переменной LIST будут имена всех каталогов в папке /svn/ пгомещенных в одну строку(для того чтобы её стравить циклу.
Как видно, все не сложно, достаточно понять принцип и написать пару своих скриптов. В заключении статьи хочу пожелать удачи в изучении BASH и Linux в целом. Критика, как водится приветствуется. Следующая статья возможно будет посвящена использованию таких программ как sed, awk.
Автор: Zloy_T
Использование потоков, конвейеров и перенаправлений в Linux
Операционные системы Unix традиционно используют такие понятия, как стандартный ввод, вывод и вывод ошибки. Чаще всего ввод — это клавиатура, а вывод это на кран. Но конечно же мы можем выводить исполнение какой-то команды в файл и передавать другой команде, потому что работая в Linux, создается такая последовательность из команд, т.е результат предыдущей мы отправляем следующей и т.д
Целью данной статьи является рассмотреть:
- Перенаправление стандартных ввода, вывода и ошибок;
- Передача вывода одной команды в качестве аргументов другой;
- Получение выходных данных в файл и на стандартный вывод;
- Stdin (0) – ввод
- Stdout(1) – вывод
- Stderr (2) – вывод ошибки
- > — передать в
- >> — дописать в
- — взять из
- | — отправить следующей команде
- Tee — отправить в файл и на стандартный вывод
- Xargs – построчно передать на ввод команде
Для начала воспользуемся командой wc которая посчитает, количество слов, символов и строк в файле wc test.txt .
Мы можем указать данной команде другой input . Мы можем ей сказать взять информацию из файла, т.е. записать вот таким образом wc т.е. данной команде передать информацию из этого файла. И данная команда отработав посчитает в принципе то же самое. В таком варианте команда не знает с каким файлом она работает ей просто поступает вывод из файла. Файл выводит свой результат этой команде. Такая стрелочка редко используется, чаще используется стрелка в другую сторону. Например, мы можем список файлов вывести командой ls . А можем сказать, чтобы данная команда отправила результат не на наш стандартный вывод т.к. результат всех наших команд по умолчанию выводится в консоль, а например в файл ls > list.txt . По сути означает выполнить команду, а результат передать в файл. Фал можно посмотреть командой cat list.txt .
И мы можем убедится, что в данном файле находится перечень, всего что находилось в данной папке. Если мы выполним еще раз команду ls > list.txt , то данный файл каждый раз будет перезаписываться. Если же мы хотим, чтобы наш файл не перезаписывался, а дописывался, используем другую стрелочку ls >> list.txt .
И теперь вы можете видеть, что файл стал больше. Т.е. у нас записалось, то что было, а затем еще раз добавилось. Если опять выполнить команду со стрелочками >> , то опять допишется информация в файл. Вот таким образом работают “стрелочки”.
Стандартный вывод ошибок.
Мы можем, например, сказать машине, выведи нам содержимое папки bob , которая не существует ls bob > result.txt , естественно мы получим ошибку которую система вывела на экран. Экран является стандартным выводом ошибок. В нашем случае нет папки bob и нет файла resut.txt . Если мы хотим отправить ошибку в файл, так же как результат выполнения команды, то ls bob 2> result.txt , вспоминаем основные понятия, в которых было указанно, что 2 – это стандартный вывод ошибки.
Следовательно, на экране мы уже не видим ошибки, потому что она отправилась в указанный файл.
Кстати мы можем объединить стандартный вывод команды и стандартный вывод ошибки. Например: ls bob > result.txt 2> error.txt . Выведи содержимое папки bob в файл result.txt , а если возникнет ошибка внеси в файл error.txt .
В таком случае и команда выполнится и что-то будет в файле и если ошибка возникнет, то она будет записана в файл error.txt . Это можно применять на практике, когда мы что-то делаем и предполагаем, что в процессе выполнения возникнут ошибки, то используя данную конструкцию данные ошибки мы все можем отправить в отдельный файл.
Конвейер
Конвейер умеет передавать выходные данные из одной программы, как входные данные для другой. Т.е. выполняется команда, мы получаем результат и передаем эти данные далее на обработку другой программе.
Например, выполнить команду ls и далее мы могли стрелочкой отправлять результаты выполнения команды в файл, т.е. мы меняли только стандартный вывод, а не передавали другой программе. А можем выполнить ls | grep r , т.е. получить содержимое и передать по конвейеру команде сортировки и сказать отсортировать по наличию буквы r , а если перенаправить еще вывод в файл, то cat имя файла , мы сможем увидеть информацию в файле.
Но есть другая команда tee которая позволяет работать немного удобнее. Например: ls | tee output.txt . Те данная команда выводит информацию сразу на экран и в указанный файл. Что достаточно удобно с точки зрения работы с выводами.
И еще одна команда xargs – она построчно работает с выводами. Если у нас есть какая-то команда, которая выдает нам вывод в виде нескольких строк ответа, то мы можем эти строки построчно передавать этой команде, т.е. не одной кашей, а построчно. Например find . –name “*.txt” найти все файлы в текущем каталоге с расширением txt . И если бы мы захотели удалить все эти файлы нам бы пришлось построчно их удалять, но мы можем сказать, чтобы выходные данные были переданы по конвейеру xargs и удалить.
find . –name “*.txt” | xargs rm -f
Как видите после данной конструкции команд файлов не осталось. Т.е. данные построчно передались на команду удаления, которая построчно каждый файл с ключом –f (принудительно) их и удалила.