Bash.Основы BASH.Часть 2. — различия между версиями

Материал из ТХАБ.РФ
Перейти к: навигация, поиск
м (Циклы. Цикл for-in.)
м (Циклы. Цикл while.)
 
Строка 39: Строка 39:
 
  echo "Do you wish to continue?"
 
  echo "Do you wish to continue?"
 
  read again
 
  read again
  done echo "Bye-Bye"
+
  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
  yes Please enter a name: mihail The name you entered is mihail Do you wish to continue? no Bye-Bye
+
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. Эта практически полный аналог цикла WHILE-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 производит арифметические операции над числами и переменными.
 
Команда 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 позволяет использовать сокращения арифметических команд, тем самым сокращая кол-во используемых переменных. Например: a = a+b эквивалентно a +=b и т.д
+
 
Работа с внешними программами при написании 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, то это можно можно след. образом:
./program_with_error 2>&1
 
символ "&" означает указатель на дескриптор 1(stdout)
 
(Поумолчанию stderr пишет на ту консоль, в котрой работает пользователь(вренее пишет на дисплей)).
 
  
2.Конвееры.
+
./program_with_error 2>&1
 +
 
 +
символ "&" означает указатель на дескриптор 1 (stdout)
 +
 
 +
(По умолчанию stderr пишет на ту консоль, в которой работает пользователь (вернее пишет на дисплей)).
 +
 
 +
== 2. Конвееры. ==
  
 
Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой:
 
Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой:
команда1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2
+
 
 +
команда 1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2
 +
 
 
Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:
 
Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:
ls -la | grep «hash» |sort > sortilg_list
 
вывод команды ls -la передается команде grep, которая отбирает все строки, в которых встретится слово hash, и передает команде сортировке sort, которая пишет результат в файл sorting_list. Все довольно понятно и просто.
 
  
Чаще всего скрипты на 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
 +
 
 +
Однако если вы захотите записать в переменную '''список каталогов''', то необходимо, должным образом обработать результат для помещения данных в переменную.
  
1. Передача вывода в переменную.
+
Рассмотрим небольшой, пример:
  
Для того чтобы записать в переменную вывод какой-либо команды, достаточно заключить команду в `` ковычки, например
+
LIST=`find /svn/ -type d 2>/dev/null| awk '{FS="/"} {print $4}'| sort|uniq | tr '\n' ' '`
a = `echo "qwerty"` echo $a
+
for ONE_OF_LIST in $LIST
Результат работы: qwerty
+
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' ' '` 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.
+
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. (Продолжения нет :-( )

См. также

Ссылки