BASH¶
http://talk.jpnc.info/bash_lfnw_2017.pdf
Make newlines the only separator:
IFS=$'\n'
Do something on exit (even if error):
function cleanup() {
# do something
}
trap cleanup EXIT
Functions boolean returns:
# 1st variant
isdirectory() {
if [ -d "$1" ]; then
return 0
else
return 1
fi
}
# 2nd variant
isdirectory() {
if [ -d "$1" ]; then
true
else
false
fi
}
# 3rd variant
isdirectory() {
[ -d "$1" ]
}
# USING
if isdirectory $1; then
echo "is directory"
else
echo "nopes"
fi
Multiple arguments passing:
ARGS=$@
# ./script.sh "one two three"
# 1. one
# 2. two
# 3. three
ARGS="$@"
# ./script.sh "one two three"
# 1. one two three
Operators:
let "var += 5"
let "var = 5 - 3"
Asynchronous bash script:
mycommand &
child_pid=$!
while kill -0 $child_pid >/dev/null 2>&1; do
echo "Child process is still running"
sleep 1
done
echo "Child process has finished"
Parsing script arguments:
#!/bin/sh
# Keeping options in alphabetical order makes it easy to add more.
while :
do
case "$1" in
-f | --file)
file="$2" # You may want to check validity of $2
shift 2
;;
-h | --help)
display_help # Call your function
exit 0
;;
-v | --verbose)
verbose="verbose"
shift
;;
--) # End of all options
shift
break;
-*)
echo "Error: Unknown option: $1" >&2
exit 1
;;
*) # No more options
break
;;
esac
done
Async/sync mode. Add ‘async=true’ before run script:
COMMAND="uptime"
SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
VMS_IPS="192.168.1.1 192.168.1.2"
CHILD_PIDS=""
VM_NUM=0
for VM_IP in $VMS_IPS; do
(( VM_NUM++ ))
if [ "$async" == "true" ]; then
ssh root@$VM_IP "$COMMAND" >> $SCRIPT_PATH/temp.$VM_NUM 2>&1 &
CHILD_PIDS="$CHILD_PIDS $!"
else
ssh $SSH_USER@$VM_IP "$COMMAND"
fi
done
if [ "$async" == "true" ]; then
for CHILD_PID in $CHILD_PIDS; do
while kill -0 $CHILD_PID >/dev/null 2>&1; do
echo "Processing in asynchronous mode..."
sleep 5.0
done
done
cat $(ls -v temp.*)
rm temp.*
fi
Check is program exists:
if hash <program> 2>/dev/null; then
echo "exists"
else
echo "not exists"
fi
Add zeros before number:
VAR=15
echo "$(seq -f %03g $VAR $VAR)"
# 015
BASH if grep ixists statement:
if grep --quiet 'text' /path/to/file; then
echo exists
else
echo not found
fi
Get path to script which run:
SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
Bash get last line from a variable:
echo "${VAR##*$'\n'}"
Is file exist:
if [ ! -f /tmp/foo.txt ]; then
echo "File not found!"
fi
Functions on BASH:
#!/bin/sh
# this will fail because foo has not been declared yet.
myFunction parameter_1 parameter_2
[function] myFunction() {
echo "Parameters: $1 $2"
}
# this will work
myFunction parameter_1 parameter_2
Do while with iterator:
COUNT=0
while [ $COUNT -lt 10 ]
do
(( COUNT++ ))
echo $COUNT
done
Boolean in BASH:
VAR=true
if [ "$VAR" = true ] ; then
echo 'true'
fi
Check if a variable is set:
if [ -z ${var+x} ]; then
echo "var is unset"
else
echo "var is set to '$var'"
fi
# this will return true if a variable is unset or set to the empty string ("")
if [ -z "$VAR" ];
For in bash:
for i in $( ls ) ; do
rm -R $i
done
Multiline file creating:
cat > /path/to/file <<EOF
line 1
line 2
EOF
# with sudo
sudo bash -c "cat > /path/to/file" << EOF
line1
line2
EOF
Make sure only root can run our script:
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit 1
fi
Stdout/stderr redirects:
# Both threads (stdout/stderr) will be redirected to a file
<command> >file 2>&1
# Stdout to file. Stderr to terminal
<command> 2>&1 >file
Logical operators for if-then-else-fi construction:
-z $VAR # string is empty
-n $VAR # string isn't empty
$VAR =/== $VAR # strings are equal
$VAR != $VAR # strings aren't equal
-eq # equal
-ne # not equal
-lt(<) # less
-le(<=) # less or equal
-gt(>) # more
-ge(>=) # more or equal
! # logical not
-a(&&) # logical and
-o(||) # logical or
-e <file> # file exists
-d <file> # file exists and is a directory
-f <file> # is a regular file (not a directory or device file)
-b <file> # file is a block device
-w <file> # file exists and the write permission is granted
-x <file> # file exists and the execute permission is granted
-r <file> # file exists and the read permission is granted
-s <file> # file exists and it's size is greater than zero (ie. it is not empty)
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html
https://www.opennet.ru/docs/RUS/bash/bash-4.html
Positional parameters
$* | $1 $2 $3 … ${N} |
$@ | $1 $2 $3 … ${N} |
“$*” | “$1c$2c$3c…c${N}” |
“$@” | “$1” “$2” “$3” … “${N}” |
set¶
set [abefhkmnptuvxldCHP] [-o опция] [аргумент]
:-a | allexport отмечает переменные, которые модифицированы или созданы для зкспорта. -b | notify вызывает прекращение фоновых заданий, о котором сообщает перед выводом следующего базового приглашения. -е | errexit немедленный выход, если выходное состояние команды ненулевое. -f | noglob выключает генерацию имени файла (глоббирование). -h обнаруживает и запоминает (хеширует) команды как определенные функции до того, как функция будет выполнена. -к В окружении команды располагаются все аргументы ключевых слов, не только те, которые предшествуют имени команды. -m | monitor Разрешается управление заданиями (см. главу 5). -n | noexec Читает команды, но не выполняет их. -о имя_опции Устанавливает флаг, соответствующий имени_опции. braceexpand оболочка должна выполнить brace-расширение (см. раздел 2.2). emacs использует интерфейс редактирования emacs (см. главу 7 "Редактирование командной строки"). ignoreeof оболочка не выходит при чтении EOF. interactive-comments позволяет вызывать слово, начинающееся с '#', и все оставшиеся символы на этой строке игнорировать в диа логовой оболочке. posix изменяет режим Bash в соответствии со стандартом Posix 1003.2, когда операция по умолчанию отличается от него. Предназначен для того, чтобы сделать режим строго подчиненным зтому стандарту. vi использует интерфейс редактирования строки редактора vi. -p | privileged Включает привилегированный режим. В зтом режиме файл $ENV не выполняется, и функции оболочки не наследуются из среды. Зто включается автоматически начальными действиями, если идентификатор зффективного пользователя (группы) не равен идентификатору реального пользователя (группы). Выключение зтой опции присваивает идентификатор зффективного пользователя (группы) идентификатору реального пользователя (группы). -t выход после чтения и выполнения команды. -u | nounset во время замещения рассматривает незаданную переменную как ошибку. -v | verbose выдает строки ввода оболочки по мере их считывания. -x | xtrace выводит команды и их аргументы по мере выполнения команд. -l сохраняет и восстанавливает связывание имени в команде for. -d | nohash Выключает хеширование команд, найденных для выполнения. Обычно команды запоминаются в хеш-таблице и, будучи однажды найденными, больше не ищутся. -С | noclobber не позволяет существующим файлам перенаправление вывода. -Н | histexpand закрывает замену стиля ! истории. Этот флаг принимается по умолчанию. -Р | physical Если установлена, не следует символьному указателю при выполнении команды типа cd, которая изменяет текущий каталог. Вместо этого используется физический каталог. -- Если нет аргументов, следующих за зтим флагом, то не задаются позиционные параметры. В противном случае позиционные параметры присваиваются аргументам, даже если некоторые из них начинаются с а-. - Сигнал конца опции, вызывающей присваивание оставшихся аргументов позиционным параметрам. Опции -x и -v выключаются. Если здесь нет аргументов, позиционный параметр не изменяется. При использовании + вместо - осуществляется выключение зтих флагов. Флаги также могут использоваться при вызове оболочки. Текущий набор флагов можно найти в $-. Оставшиеся N переменных - позиционные параметры и присваиваются по порядку $1, $2,...,$N. Если аргументы не даны, выводятся все переменные оболочки.