Bash скрипты

При запуске скрипта создается дочерняя консоль, в ней выполняется скрипт и результат возвращается в консоль. 

 Можно запускать через source, имя (если . в PATH), ./... , и ./ ... & С фоновой задачей аккуратно с объемом вывода, ^C не работает. 

 Shebang 

 Лучше использовать shebang в начале (указатель, какую консоль использовать) 

 #!/bin/bash 

 

 

 

 #!/bin/bash -x 

 Выводит все команды во время исполнения 

 

 

 #!/bin/bash -r 

 Блокирует потенциально опасные действия 

 

 

 

 Параметры можно указывать при запуске скрипта, тогда shebang работать не будет. 

 Удобства 

 Комментарии # 

 bash -n script.sh проверка синтаксиса без исполнения скрипта 

 Внутри можно использовать следующую конструкцию для вывода части скрипта:  

 #!/bin/bash

...

set -x

...potentially error part...

set +x 

 Операция ; запускает несколько команд независимо от их статуса завершения  

 ls; ps; whoami 

 выполнит все команды 

 Перенаправления результата выполнения   

 

 

 

 > 

 Stdout в файл, файл очищается 

 

 

 >> 

 Stdout в файл, файл дополняется 

 

 

 &> or >& 

 Stdout и Stderr в файл, файл очищается 

 

 

 &>> 

 Stdout и Stderr в файл, файл дополняется 

 

 

 < 

 Перенаправление ввода в команду 

 

 

 << 

 Перенаправление многострочного ввода в команду 

 

 

 

 Номера потоков 

 0 - stdin, 1 - stdout, 2 - stderr 

 lzl -l 1> stdout.txt 2>stderr.txt 

 выведет в stderr.txt 

 Функции 

 function functname{

shell commands

}

functname(){

shell commands

} 

 Используют позиционные переменные.  

 functname "one" $7 

 Если внутри функции нужна локальная переменная, то local var1="something", иначе используется глобальная переменная. 

 Статус возврата из функции перезаписывается после каждого вызова команды, поэтому при необходимости возврата статуса некоторой функции внутри нужно сохранять статус. 

 cd baddir

echo $? 

 По умолчанию возвращается статус вызова последней команды. Либо через return N  

 builtin mkdir "/var/first"

es=$?

echo "$OLDPWD --> $PWD"

return $es

 

 Желательно возвращать код результата, а не просто цифру. 

 Программы для работы с функциями 

 

 

 

 declare 

 -f список функций с описанием 

 

 

 

 -F только имена функций 

 

 

 unset fname 

 удалить функцию из памяти 

 

 

 type fname 

 Описание функции 

 

 

 

 -t выведет тип 

 

 

 

 

 Приоритет при вызове из консоли 

 

 Aliases 

 Служебные слова типа if, ... 

 Функции 

 Встроенные команды типа cd, type, ... 

 Скрипты и исполняемые команды 

 

 Переменные 

 Строковые (по умолчанию) 

 Описывается $varname или ${varname} Например есть переменная UID. Для вывода 0_ нужно использовать echo ${varname}_ 

 Удаление переменной unset var1 

 

 

 

 $1, $2, ... 

 Позиционные параметры 

 

 

 $* 

 Строка, содержащая все параметры через пробел 

 

 

 $@ 

 Равна N строкам-параметрам. Актуально при передаче в функции. 

 

 

 $# 

 Количество аргументов 

 

 

 var1=$(cmd) 

 Сохранение результата cmd в переменную 

 

 

 

 Определение глобальной переменной: var1="something" 

 Обработка значений переменных перед вводом 

 

 

 

 ${varname:-word } 

 Если переменная не существует или существует но пустая - вернет word 

 

 

 ${varname:=word} 

 Если переменная не существует или существует но пустая - присвоит ей word и вернет word 

 

 

 ${varname:?message} 

 Если переменная не существует или существует но пустая - выведет сообщение и завершит скрипт 

 

 

 ${varname:+word} 

 Если переменная существует или пустая - вернет word, иначе null 

 

 

 ${varname:offset:length} 

 

 Срез.  

 count=frogfootman 

 ${count:4} вернет footman 

 ${count:4:4} вернет foot 

 

 

 

 

 Обработка переменных  

 

 

 

 

 ${var#pattern} 

   

 

 

 

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

 var="/home/user/docs/file.txt" echo ${var#*/}   # home/user/docs/file.txt   (отрезан только первый "/") 

 

 

 

 ${var##pattern} 

 

 var="/home/user/docs/file.txt" 

 echo ${var##*/}  # file.txt                  (отрезано всё до последнего "/") 

 

 

 

 ${variable%pattern} 

 

 file="archive.tar.gz" 

 echo ${file%.*}   # archive.tar 

 

 

 

 ${variable%%pattern} 

 

 file="archive.tar.gz" 

 echo ${file%%.*}  # archive  

 

 

 

 ${variable/pattern/string} 

 

 Наибольшее совпадение шаблона с переменной заменяется строкой. Первое совпадение 

 

 

 

 ${variable//pattern/ string} 

 

 Наибольшее совпадение шаблона с переменной заменяется строкой. Все совпадения 

 

 

 

 

 

  echo -e ${PATH//:/'\n'} 

 выведет разделенное через : значение в значения списком 

 

 

 

 

 Длина значения ${#filename} 

 Типизированные 

 При помощи declare <param> var 

 

 

 

 -a 

 Массив 

 

 

 -i 

 Целое число 

 

 

 -r 

 Переменная только для чтения 

 

 

 -x 

 Переменная экспортируется в окружение 

 

 

 -f 

 

 Хрень. Возвращает тело функции если она есть. 

 myfunc() {

 echo "Hello from myfunc"

}

declare -f myfunc 

 

 

 

 -F 

 Возвратит имя функции если она есть. 

 

 

 

 Пример:  

 declare -i val3=12 val4=5

declare -i result2

result2=val3*val

echo $result2 

 Выведет 60 

 Использование let  

 let result="4 * 5"

echo $result 

 Также можно использовать двойные скобки  

 let result=$((4 * 5))

echo $result 

 Есть операции +,-,/,*,%-модуль, += увеличение на константу, -= 

 Массивы 

 arr = (1 2 3)

echo "${arr[*]}" #весь массив

echo "${arr[0]}" #1

unset ${arr[1]} #удалит 2 из массива

${arr[0]}=10 #перезапишет 1 в 10 

 

 Условия 

 Условия завершения программы 

 Условие анализируется не на логическом, а на статусе результата (exit status) выполнения программы. 0 - ОК, 1-255 ошибка. 

 if condition; then

statements

[elif condition; then 

statements...]

[else

statements]

fi 

 Условие анализа строк 

  конструкция [], внутри нее возможны условия проверки и сравнения строк. 

 

 

 

 str1 = str2 

 Строка 1 равна строке 2 

 

 

 str1 != str2 

 Строка 1 не равна строке 2 

 

 

 str1 > str2 str1 < str2 

 Больше/меньше 

 

 

 -n str1 

 Строка 1 не пустая 

 

 

 -z str1 

 Строка 1 пустая 

 

 

 

 Условия сравнения чисел 

 

 

 

 -lt 

 Менее чем 

 

 

 -le 

 Меньше или равно 

 

 

 -eq 

 Равно 

 

 

 -ge 

 Больше или равно 

 

 

 -gt 

 Больше 

 

 

 -ne 

 Не равно 

 

 

 

 Можно комбинировать  

 if command && [ condition ]; then 

 Логика внутри условия 

 

 

 

 && или -a 

 

 Выполнить команду 1, если статус 0 - выполнить команду 2 

 if statement1 && statement2

then

...

fi 

 

 

 

 || или -o 

 

 Выполнить команду 1, если статус не 0 - выполнить команду 2 

 if statement1 || statement2

then

...

fi 

 

 

 

 ! 

 

 Отрицание 

 

 

 

 

 Свойства файла, проверяемые в условиях 

 

 

 

 -a file, -e file 

 Файл существует 

 

 

 -d file 

 Директория существует 

 

 

 -f file 

 Файл существует и является файлом (не директория или специальный файл) 

 

 

 -r file, -w file 

 Есть право чтения файла, Есть право записи в файл,  

 

 

 -x file 

 Есть право исполнения файла или право поиска в директории 

 

 

 -s file 

 Файл существует и не пустой 

 

 

 -N file 

 Файл был изменен с момента последнего чтения 

 

 

 -O file, -G file 

 Запустивший скрипт является владельцем файла, Группа запустившего скрипт входит в группу файла 

 

 

 file1 -nt file2 

 file1 новее file2 (сравниваются время модификации) 

 

 

 file1 -ot file2 

 file1 старее file2 (сравниваются время модификации) 

 

 

 

 Цикл for 

 Итерируется только по полному списку. 

 for name [in list]; do

 statements that can use $name...

 done 

 Если list не определен, то используется $@ 

 Есть переменная IFS  

 IFS=:

for dir in $PATH

 do

 ls -ld $dir

 done 

 break выход из цикла, continue продолжить следующую итерацию 

 Цикл while 

 while condition; do

statements...

done 

 Для бесконечного цикла можно использовать while true; do 

 Просмотр каждой строки вывода программы (например ping)  

 #!/bin/bash

ping 172.16.10.1 | while read -r line; do

 echo Пинг $line | awk '{print $1 $6}'

 done

 

 

 Цикл until 

 until command; do

statements...

done

 

 Case 

 for filename in "$@"; do

 pnmfile=${filename%.*}.ppm

 case $filename in

 *.jpg ) exit 0 ;;

 *.tga ) tgatoppm $filename > $pnmfile ;;

 *.xpm ) xpmtoppm $filename > $pnmfile ;;

 *.pcx ) pcxtoppm $filename > $pnmfile ;;

 *.tif ) tifftopnm $filename > $pnmfile ;;

 *.gif ) giftopnm $filename > $pnmfile ;;

 * ) echo "procfile: $filename is an unknown graphics file." 

 exit 1 ;;

 esac

 outfile=${pnmfile%.ppm}.new.jpg

 pnmtojpeg $pnmfile > $outfile

 rm $pnmfile

done 

 Опции исполнения 

 shift смещает переменные влево. 

 myshift.sh

echo $1 $2

shift

echo $1 $2

Использование: ./myshift.sh one two

Вывод:

one two

two 

 Вариант скрипта, считывающего параметры со случайным размещением параметров  

 while [ -n "$(echo $1 | grep '-')" ]; do

 case $1 in

 -a ) aopt=$2

 shift;;

 -b ) bopt="True"

 ;;

 -c ) copt=$2

 shift;;

 * ) echo 'usage: alice [-a] [-b] [-c] args...'

 exit 1

 esac

 shift

done 

 Опция -b является одинарной, -a и -c параметризованные. 

 В процессе исполнения можно добавлять интерактивность за счет считывания аргументов  

 echo "First arg"

read -r farg

echo "First arg is ${farg}" 

 Вызов другого скрипта 

 Если есть права на исполнение и правильный shebang то вызов по имени. Скрипт исполняется в подпроцессе. 

 #!/bin/bash

echo "Это первый скрипт"

./script2.sh # вызов второго скрипта 

 Если директория script2.sh не в PATH то нужен полный путь. 

 Для выполнения скрипта в одном процессе, все переменные передаются:  

 #!/bin/bash

echo "Это первый скрипт"

source script2.sh 

 Также можно передавать аргументы.