Учебник по BASH
Учебник написан для сайта: http://snakeproject.ru/
Автор: Козлов Михаил
Отблагодарить автора можно на форме перевода в
"подвале" сайта
### Первый скрипт
Скрипты в баш
начинаются с указания интерпретатора:
#!/usr/local/bin/bash
Узнать, где находится
bash можно командой:
which bash
Сделать скрипт
исполняемым можно добавив права:
chmod +x test.sh
Комментарии
начинаются с символа - #
Пример написания
простейшего скрипта:
cd /home/user
vi
test.sh
#!/usr/local/bin/bash
#This is first script
echo
"This is echo line"
chmod +x test.sh
Варианты запуска:
./test.sh
This is
echo line
bash
./test.sh
This is
echo line
Вариант запуска с
отладкой:
bash -x ./test.sh
+ echo 'This is echo line'
Добавим простейшую
функцию:
#!/usr/local/bin/bash
#This is first script
echo
"This is echo line"
### Простые функции и передача аргументов
В данном скрипте мы
сделаем пару функций:
cat
test.sh
#!/usr/local/bin/bash
# Не принимает аргументов
function echo_text()
{
echo "This is
echo line"
}
# Принимает аргументы, выводит их
function echo_text_args()
{
echo "This is
echo linei args: $1
$2"
}
# Вызов функций
echo_text
echo_text_args "1_arg" "2_arg"
echo_text_args $1 $2
Вызов скрипта с
передачей аргументов и без:
./test.sh
This is
echo line
This is
echo linei args: 1_arg
2_arg
This is
echo linei args:
./test.sh
1_global_arg 2_global_arg
This is
echo line
This is
echo linei args: 1_arg
2_arg
This is
echo linei args:
1_global_arg 2_global_arg
Как видно, имена
аргументов в скрипте одинаковы, результат - разный
Глобально и локально
в функции это разные переменные
### Переменные
set - выводит установленные переменные
Введите в терминале set или set | more
Вывести значение переменной - "$":
echo
$HOME
echo
$LOGNAME mail box is: $MAIL
Назначить значение
переменной - "=":
var1=variable_1_value
var2=$var1
echo $var1 $var2
Пример с числовыми
переменными:
# Выведется как
строка
var1="1"
var2=2
var3=$var1+$var2
echo $var3
# Выведется как
строка
var1=1
var2=2
var3=$var1+$var2
echo
$var3
# Выведется как число
var1="1"
var2=2
var3=$(($var1+$var2))
echo $var3
# Выведется как число
var1=1
var2=2
var3=$(($var1+$var2))
echo $var3
Переменные скрипта:
$@ - список переданных аргументов
$# - количество переданных аргументов
$0 - имя скрипта
$цифра - номер переданного скрипту аргумента
Пример скрипта:
#!/usr/local/bin/bash
echo $@
echo $#
echo $0
echo $1
echo $2
echo $3
Пример вызовов
скрипта:
./test.sh
0
./test.sh
./test.sh
arg1
arg1
1
./test.sh
arg1
./test.sh
arg1 arg2
arg1 arg2
2
./test.sh
arg1
arg2
Пример смещения аргумента - shift:
#!/usr/local/bin/bash
echo $@
$# $0 $1 $2
shift
echo $@
$# $0 $1 $2
Пример скрипта:
./test.sh
arg1 arg2
arg1 arg2 2
./test.sh arg1 arg2
arg2 1 ./test.sh arg2
Как видим, первый
аргумент пропал
Пример перебора
переданных аргументов с помощью shift:
#!/usr/local/bin/bash
function get_value(){
echo $1
shift
}
for val in $@;
do
get_value
$val
done;
Пример вызова:
./test.sh arg1 arg2
arg1
arg2
Цикл for перебрал все слова в переменной "$@" через
"пробел"
### Ввод, вывод, ошибка
0 — STDIN(ввод), 1 —
STDOUT(вывод) и 2 — STDERR(ошибка)
По умолчанию
используется STDOUT
Осуществляется опреаторами:
< > << >>
1> - перенаправление стандартного вывода
2> - перенаправление вывода ошибок
Отправить вывод
команды в файл (затрет все в файле):
echo 'test' > file.txt
Отправить вывод
команды в файл (добавит информацию в файл):
echo 'test_2' >> file.txt
Отправить вывод
команды в никуда:
echo 'test' > /dev/null
Пример: отправлять
стандартный вывод в /dev/null,
ошибки(STDERR) в стандартный вывод(&1)
echo 'test' > /dev/null 2>&1
Пример: отправлять стандартный
вывод и ошибки в /dev/null:
echo 'test' &> /dev/null
Пример, приведем
скрипт к такому виду, который выдаст ошибку деления на 0:
test.sh:
#!/usr/local/bin/bash
var1=1
var2=0
echo
'Zero division'
echo
$((var1/var2))
Допустим мы
подключены удаленно по ssh(&2):
./test.sh
Zero
division
./test.sh:
line 7: var1/var2: division by 0 (error token is "var2")
./test.sh
> /dev/null
./test.sh:
line 7: var1/var2: division by 0 (error token is "var2")
./test.sh
> /dev/null 2>&1
./test.sh
> /dev/null 2>&2
./test.sh:
line 7: var1/var2: division by 0 (error token is "var2")
./test.sh
> /dev/null 2>/dev/null
Рассмотрим ввод
пользователя:
test.sh:
#!/usr/local/bin/bash
echo
'write number 1:'
read var1
echo
'write number 2:'
read var2
var3=`expr
$var1 + $var2`
echo
"summ is: " $var3
Проверяем:
./test.sh
write
number 1:
1
write
number 2:
2
summ is: 3
expr — программа в UNIX подобных ОС
Вычисляет значение
выражения и выводит результат в стандартный вывод
### Логическая конструкция if
Логические операторы:
# строка пуста: -z
# строка не пуста: -n
# строки равны: =, (==)
# строки неравны: !=
# равно: -eq
# неравно: -ne
# меньше: -lt,(< )
# меньше или равно: -le,(<=)
# больше: -gt,(>)
# больше или равно: -ge,(>=)
# отрицание логического выражения: !
# логическое "И": -a,(&&)
# логическое "ИЛИ": -o,(||)
Конструкция if elif else:
#!/usr/local/bin/bash
a=6
if [ $a -eq 5 ]
then
echo "a is
5"
elif [ $a -eq 6 ]
then
echo "a is
6"
else
echo "a is not
5 and 6"
fi
./test.sh
a is 6
if, then, fi - обязательные конструкции
elif и else -
необязательные конструкции
Переделаем скрипт
Введем проверку на
количество принимаемых аргументов:
#!/usr/local/bin/bash
if [[ $#
-ne 1 ]]
then
echo 'Wrong number
of arguments! Enter one'
exit 2
fi
if [ $1 -eq 5 ]
then
echo "arg is 5"
elif [ $1 -eq 6 ]
then
echo "arg is 6"
else
echo "arg is not 5 and 6"
fi
Проверяем:
./test.sh
Wrong
number of arguments! Enter one
./test.sh 1
2
Wrong
number of arguments! Enter one
./test.sh 1
arg is not 5 and 6
./test.sh 5
arg is 5
exit
любой скрипт возращает успешный код 0, любой другой возвращаемый код -
ошибка
Замена скобок на test (отработает эквивалентно примеру со скобками):
#!/usr/local/bin/bash
if [[ $#
-ne 1 ]]
then
echo 'Wrong number
of arguments! Enter one'
exit 2
fi
if test
$1 -eq 5
then
echo "arg is 5"
elif [ $1 -eq 6 ]
then
echo "arg is 6"
else
echo "arg is not 5 and 6"
fi
Двойные квадратные
скобки - конструкция только языка bash
### Логическая конструкция case (аналог конструкции if)
Пример проверки
значения переменной:
#!/usr/local/bin/bash
a=3
case $a
in
1)
echo "a is
1"
;;
2)
echo "a is
2"
;;
*)
echo "a is
not 1 and 2"
;;
esac
Проверяем:
./test.sh
a is not
1 and 2
*) - аналогична else в конструкции if
Совпадение с любым
значением, не прошедшим предыдущие условия
### Циклы while и until
Цикл while можно описать как "выполняй, пока условие
истинно"
Цикл while:
#!/usr/local/bin/bash
a=0;
while [
"$a" -le 5 ]; do
echo "value of
a: $a"
a=$(expr $a + 1)
done
./test.sh
value of
a: 0
value of
a: 1
value of
a: 2
value of
a: 3
value of
a: 4
value of
a: 5
Цикл until можно описать как "выполняй, пока условие
ложно"
#!/usr/local/bin/bash
a=3
until [
$a -ge 6 ]; do
echo "value of
a: $a"
a=$(expr $a + 1)
done
./test.sh
value of
a: 3
value of
a: 4
value of a: 5
### Цикл for
По сути цикл -
переборщик значений
Пример перебора
числовых значений:
#!/usr/local/bin/bash
for a in
1 2 3 4 5 6 7 8 9; do
if [ $a -eq 5 ]
then
echo "5
detected!!!"
fi
done
./test.sh
5 detected!!!
Пример перебора
текстовых значений:
#!/usr/local/bin/bash
var='arg1 arg2 arg3'
for a in
$var; do
if [ $a ==
"arg2" ]
then
echo "arg2
detected!!!"
fi
done
./test.sh
arg2 detected!!!
Пример перебора с
условием, делай, пока верно:
#!/usr/local/bin/bash
for ((i=1;i<=3;i++))
do
echo $i
done
Проверяем:
./test.sh
1
2
3
Применим для опроса
сети по icmp:
#!/usr/local/bin/bash
for ((i=1;i<=3;i++))
do
echo -n "ping
10.0.2.$i "
if ping -W 1 -c 1
10.0.2.$i > /dev/null
then
echo "Ping
success"
else
echo "Ping
failed"
fi
done
Вызов:
./test.sh
ping 10.0.2.1 Ping success
ping 10.0.2.2 Ping success
ping 10.0.2.3 Ping failed
### Массивы
Задать массив,
вариант 1:
Arr[0]='arg1'
Arr[1]='arg2'
Вариант 2:
declare
-a Arr=('arg1' 'arg2');
Вариант 3:
Arr=(arg1 arg2)
Вывести длину массива
или длину элемента ${#}:
echo ${#Arr[@]}
echo ${#Arr[1]}
Вывести все элементы:
echo ${Arr[@]}
Вывести элементы в
диапазоне с 0 по 2:
echo ${Arr[@]:0:2}
Заменить все символы
в выводе:
echo ${Arr[@]//g/gs}
Перебор массива:
for i in ${Arr[@]}
do
echo $i
done
Удалим элемент
массива:
unset Arr[1]
Добавить в конец элемент
в массив:
Arr+=(arg3)
Добавить по позиции
элемент в массив:
Arr+=([1]=arg2)
Сохранить все
элементы из вывода команды в массив:
Arr=( $(ls /) )
### Выполнение команды из скрипта
Пример:
#!/usr/local/bin/bash
my_current_dir=$(pwd)
echo $my_current_dir
Проверка:
./test.sh
/home/user