Учебник по 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'

 

 

Пользуйтесь для дебага опцией -x

В больших и незнакомых скриптах она бесценна

 

 

Добавим простейшую функцию:

#!/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