summaryrefslogtreecommitdiff
path: root/LINUX/BASH_script/BASH. Часть 1.md
blob: abc45f8886b878c83e6cf7c5143b682875980579 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
## Введение

BASH — Bourne-Again SHell (что может переводится как «перерожденный шел», или «Снова шел Борна(создатель sh)»), самый популярный командный интерпретатор в юниксоподобных системах, в особенности в GNU/Linux. Ниже приведу ряд встроенных команд, которые мы будем использовать для создания своих скриптов.


>`break` выход из цикла for, while или until  
> `continue` выполнение следующей итерации цикла for, while или until  
> `echo` вывод аргументов, разделенных пробелами, на стандартное устройство вывода  
> `exit` выход из оболочки  
> `export` отмечает аргументы как переменные для передачи в дочерние процессы в среде  
> `hash` запоминает полные имена путей команд, указанных в качестве аргументов, чтобы не искать их при следующем обращении  
> `kill` посылает сигнал завершения процессу  
> `pwd` выводит текущий рабочий каталог  
> `read` читает строку из ввода оболочки и использует ее для присвоения значений указанным переменным.\  
> `return` заставляет функцию оболочки выйти с указанным значением  
> `shift` перемещает позиционные параметры налево  
> `test` вычисляет условное выражение  
> `times` выводит имя пользователя и системное время, использованное оболочкой и ее потомками  
> `trap` указывает команды, которые должны выполняться при получении оболочкой сигнала  
> `unset` вызывает уничтожение переменных оболочки  
> `wait` ждет выхода из дочернего процесса и сообщает выходное состояние.  


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

## Что необходимо знать с самого начала

1. Любой bash-скрипт должен начинаться со строки:

> `#!/bin/bash`

*в этой строке после #! указывается путь к bash-интерпретатору, поэтому если он у вас установлен в другом месте(где, вы можете узнать набрав `whereis bash`) поменяйте её на ваш путь.*

2. Коментарии начинаются с символа # (кроме первой строки).
3. В bash переменные не имеют типа(о них речь пойдет ниже)

## Переменные и параметры скрипта

Приведу как пример небольшой пример, который мы разберем:

> `#!/bin/bash` #указываем где у нас хранится bash-интерпретатор  
> \#присваиваем переменной parametr1 значение первого параметра скрипта  
> `parametr1=$1`  
> \#присваиваем переменной script_name значение имени скрипта  
> `script_name=$0`  
> \# команда echo выводит определенную строку, обращение к переменным осуществляется через $имя_переменной.  
> `echo "Вы запустили скрипт с именем $script_name и параметром $parametr1"`  
> \# здесь мы видим другие кавычки, разница в том, что в одинарных кавычках не происходит подстановки переменных.  
> `echo 'Вы запустили скрипт с именем $script_name и параметром $parametr1'`  
> \#Выход с кодом 0 (удачное завершение работы скрипта)  
> `exit 0`  


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

> `ite@ite-desktop:~$ ./test.sh qwerty`  
> Вы запустили скрипт с именем ./test.sh и параметром qwerty  
> Вы запустили скрипт с именем $script_name и параметром $parametr1


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

> `$DIRSTACK` - содержимое вершины стека каталогов  
> `$EDITOR` - текстовый редактор по умолчанию  
> `$EUID` - Эффективный UID. Если вы использовали программу su для выполнения команд от другого пользователя, то эта переменная содержит UID этого пользователя, в то время как...  
> `$UID` - ...содержит реальный идентификатор, который устанавливается только при логине.  
> `$FUNCNAME` - имя текущей функции в скрипте.  
> `$GROUPS` - массив групп к которым принадлежит текущий пользователь  
> `$HOME` - домашний каталог пользователя  
> `$HOSTNAME` - ваш hostname  
> `$HOSTTYPE` - архитектура машины.  
> `$LC_CTYPE` - внутренняя переменная, котороя определяет кодировку символов  
> `$OLDPWD` - прежний рабочий каталог  
> `$OSTYPE` - тип ОС  
> `$PATH` - путь поиска программ  
> `$PPID` - идентификатор родительского процесса  
> `$SECONDS` - время работы скрипта(в сек.)  
> `$#` - общее количество параметров переданных скрипту  
> `$*` - все аргументы переданыне скрипту(выводятся в строку)  
> `$@` - тоже самое, что и предыдущий, но параметры выводятся в столбик  
> `$!` - PID последнего запущенного в фоне процесса  
> `$$` - PID самого скрипта  

> IFS=$'\n'   - переназначение переменной среды на 'только перевод строки'
> IFS=:  - переназначение переменной среды на ' : '

## Условия

Условные операторы, думаю, знакомы практически каждому, кто хоть раз пытался на чем-то писать программы. В bash условия пишутся след. образом (как обычно на примере):


> `#!/bin/bash`  
> \#в переменную source засовываем первый параметр скрипта  
> `source=$1`  
> \#в переменную dest засовываем второй параметр скрипта  
> `dest=$2`  
>
> \# в ковычках указываем имена переменных для сравнения. -eq - логическое сравнение обозначающие "равны"  
> `if [[ "$source" -eq "$dest" ]]`  
> \# если они действительно равны, то  
> `then`  
> \#выводим сообщение об ошибке, т.к. $source и $dest у нас равны  
> `echo "Применик $dest и источник $source один и тот же файл!"`  
> \# выходим с ошибкой (1 - код ошибки)  
> `exit 1`  
> \# если же они не равны  
> `else`  
> \# то выполняем команду cp: копируем источник в приемник  
> `cp $source $dest`  
> `echo "Удачное копирование!"`  
> `fi` #обозначаем окончание условия.  


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


> `ite@ite-desktop:~$ ./primer2.sh 1 1`  
> Применик 1 и источник 1 один и тот же файл!  

> `ite@ite-desktop:~$ ./primer2.sh 1 2`  
> Удачное копирование!  

Структура `if-then-else` используется следующим образом:  

> `if` <команда или набор команд возвращающих код возврата(0 или 1)>  
> `then`  
> <если выражение после if истино, то выполняется этот блок>  
> `else`  
> <если выражение после if ложно, тот этот>  


В качестве команд возвращающих код возврата могут выступать структуры `[[ , [ , test, (( ))` или любая другая(или несколько) linux-команда.  


> `test` - используется для логического сравнения. после выражения, неоьбходима закрывающая скобка "]"  
>`[` - синоним команды test  
>`[[` - расширенная версия "[" (начиная с версии 2.02)(как в примере), внутри которой могут быть использованы || (или), & (и). Долна иметь закрывающуб скобку "]]"  
>`(( ))` - математическое сравнение.  


для построения многоярусных условий вида:

> `if ...`  
>`then ....`  
>`else`  
>`if ....`  
>`then....`  
>`else ....`  

для краткости и читаемости кода, можно использовать структуру:

> `if ..`  
> `then ...`  
> `elif ...`  
> `then ...`  
> `elif ...`  


## Условия. Множественный выбор

Если необходимо сравнивать какоую-то одну переменную с большим количеством параметров, то целесообразней использовать оператор case.

> `#!/bin/bash`  
> `echo "Выберите редатор для запуска:"`  
> `echo "1 Запуск программы nano"`  
> `echo "2 Запуск программы vi"`  
> `echo "3 Запуск программы emacs"`  
> `echo "4 Выход"`  
\#здесь мы читаем в переменную $doing со стандартного ввода  
> `read doing`  
>
> `case $doing in`  
> `1)`  
> `/usr/bin/nano` # если $doing содержит 1, то запустить nano  
> `;;`  
> `2)`  
> `/usr/bin/vi` # если $doing содержит 2, то запустить vi  
> `;;`  
> `3)`  
> `/usr/bin/emacs` # если $doing содержит 3, то запустить emacs  
> `;;`  
> `4)`  
> `exit 0`  
> `;;`  
> `*)` #если введено с клавиатуры то, что в case не описывается, выполнять следующее:  
> `echo "Введено неправильное действие"`  
>
> `esac` #окончание оператора case.  

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

> `ite@ite-desktop:~$ ./menu2.sh`  
> Выберите редатор для запуска:  
> 1 Запуск программы nano  
> 2 Запуск программы vi  
> 3 Запуск программы emacs  
> 4 Выход  

После выбор цифры и нажатия Enter запуститься тот редактор, который вы выбрали(если конечно все пути указаны правильно, и у вас установлены эти редакторы :) )  


Прведу список логических операторв, которые используются для конструкции if-then-else-fi:

> `-z` # строка пуста  
> `-n` # строка не пуста  
> `=, (==)` # строки равны  
> `!=` # строки неравны  
> 
> `-eq` # равно  
> `-ne` # неравно  
> `-lt,(< )` # меньше  
> `-le,(<=)` # меньше или равно  
> `-gt,(>)` # больше  
> `-ge,(>=)` # больше или равно  
> `!` # отрицание логического выражения  
> 
> `-a,(&&)` # логическое «И»  
> `-o,(||)` # логическое «ИЛИ»  


С основами языка и условиями мы разобрались, чтобы не перегружать статью, разобью её на несколько частей(допустим на 3). Во второй части разберем операторы цикла и выполнение математических операций.