Начало работы
hello.sh
``bash #!/bin/bash
VAR=“world” echo “Hello $VAR!” # => Hello world!
Выполнить скрипт
``Основной сценарий
$ bash hello.sh
Переменные
``bash NAME=“John”
echo ${NAME} # => Джон (переменные) echo $NAME # => Джон (Переменные) echo “$NAME” # => Джон (переменные) echo ‘$NAME’ # => $NAME (Точная строка) echo “${NAME}!” # => John! (Переменные)
NAME = “John” # => Ошибка (о пробеле)
### Комментарии
``bash
# Это встроенный комментарий Bash.
- ``bash
- ' Это очень аккуратный комментарий в bash '
В многострочных комментариях используется `:'` для открытия и `'` для закрытия
### Аргументы {.row-span-2}
| Выражение | Описание |
|-------------|---------------------------------------|
| `$1` ... `$9` | Параметр 1 ... 9 |
| `$0` | Имя самого скрипта |
| `$1` | Первый аргумент |
| | `${10}` | Позиционный параметр 10 |
| | `$#` | Количество аргументов |
| `$$` | Идентификатор процесса оболочки |
| `$*` | Все аргументы |
| | `$@` | Все аргументы, начиная с первого |
| `$-` | Текущие опции |
| `$_` | Последний аргумент предыдущей команды |
См: [Специальные параметры](http://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables)
### Функции
``bash
get_name() {
echo "John"
}
echo "Вы - $(get_name)"
См: Функции
Условные обозначения
``bash if [[ -z “$string” ]]; then echo “Строка пуста” elif [[ -n “$string” ]]; then echo “Строка не пуста” fi
См: [Conditionals](#bash-conditionals)
### Расширение скобок
``bash
echo {A,B}.js
Выражение | Описание |
---|---|
{A,B} |
То же, что A B |
{A,B}.js |
То же, что A.js B.js |
{1..5} |
То же, что 1 2 3 4 5 |
См: Brace expansion
Выполнение оболочки
``bash
=> Я нахожусь в /path/of/current
echo “I’m in $(PWD)”
То же самое, что:
echo “I’m in pwd
”
См: [Подстановка команд](http://wiki.bash-hackers.org/syntax/expansion/cmdsubst)
Расширения параметров Bash
--------------------
### Синтаксис {.row-span-2}
| Код | Описание |
|-------------------|---------------------|
| `${FOO%suffix}` | Удалить суффикс |
| `${FOO#prefix}` | Удалить префикс |
| `${FOO%suffix}` | Удалить длинный суффикс |
| `${FOO##prefix}` | Удалить длинный префикс |
| `${FOO/from/to}` | Заменить первое совпадение |
| `${FOO//from/to}` | Заменить все |
| `${FOO/%from/to}` | Заменить суффикс |
| `${FOO/#from/to}` | Заменить префикс |
#### Подстроки
| Выражение | Описание |
|-----------------|--------------------------------|
| `${FOO:0:3}` | Substring _(position, length)_ |
| `${FOO:(-3):3}` | Подстрока справа |
#### Длина
| Выражение | Описание |
|------------|------------------|
| `${#FOO}` | Длина `$FOO` |
#### Значения по умолчанию
| Выражение | Описание |
|-------------------|------------------------------------------|
| | `${FOO:-val}` | `$FOO`, или `val`, если не задано |
| `${FOO:=val}` | Установить `$FOO` в `val`, если не установлено |
| `${FOO:+val}` | `val`, если `$FOO` установлен |
| `${FOO:?message}` | Показать сообщение и выйти, если `$FOO` не установлено |
### Подстановка
``bash
echo ${food:-Cake} #=> $food или "Cake"
``bash STR="/path/to/foo.cpp" echo ${STR%.cpp} # /path/to/foo echo ${STR%.cpp}.o # /path/to/foo.o echo ${STR%/*} # /path/to
echo ${STR##.} # cpp (расширение) echo ${STR##/} # foo.cpp (basepath)
echo ${STR#/} # path/to/foo.cpp echo ${STR##/} # foo.cpp
echo ${STR/foo/bar} # /path/to/bar.cpp
### Нарезка
``bash
name="John"
echo ${name} # => John
echo ${name:0:2} # => Jo
echo ${name::2} # => Jo
echo ${name::-1} # => Joh
echo ${name:(-1)} # => n
echo ${name:(-2)} # => hn
echo ${name:(-2):2} # => hn
длина=2
echo ${name:0:length} # => Jo
basepath & dirpath
``bash SRC="/path/to/foo.cpp"
``bash
BASEPATH=${SRC##*/}
echo $BASEPATH # => "foo.cpp"
DIRPATH=${SRC%$BASEPATH}
echo $DIRPATH # => "/path/to/"
Трансформация
``bash STR=“HELLO WORLD!” echo ${STR,} # => hELLO WORLD! echo ${STR,,} # => hello world!
STR=“hello world!” echo ${STR^} # => Hello world! echo ${STR^^} # => HELLO WORLD!
ARR=(hello World) echo “${ARR[@],}” # => hello world echo “${ARR[@]^}” # => Hello World
Массивы Bash
------
### Определение массивов
``bash
Fruits=('Apple' 'Banana' 'Orange')
Fruits[0]="Apple"
Fruits[1]="Банан"
Fruits[2]="Orange"
ARRAY1=(foo{1..2}) # => foo1 foo2
ARRAY2=({A..D}) # => A B C D
# Объединение => foo1 foo2 A B C D
ARRAY3=(${ARRAY1[@]} ${ARRAY2[@]})
# объявить конструкцию
declare -a Numbers=(1 2 3)
Numbers+=(4 5) # Append => 1 2 3 4 5
Индексирование
- | - |
---|---|
${Фрукты[0]} |
Первый элемент |
${Fruits[-1]} |
Последний элемент |
${Fruits[*]} |
Все элементы |
${Fruits[@]} |
Все элементы |
${#Fruits[@]} |
|
${#Fruits} |
|
${#Fruits[3]} |
|
${Фрукты[@]:3:2} |
Диапазон |
${!Fruits[@]} |
Ключи всех |
Итерация
``bash Fruits=(‘Apple’ ‘Banana’ ‘Orange’)
for e in “${Фрукты[@]}”; do echo $e done
#### С индексом
``bash
for i in "${!Fruits[@]}"; do
printf "%s\t%s\n" "$i" "${Фрукты[$i]}"
done
Операции
``bash
Fruits=("${Fruits[@]}" “Арбуз”) # Push
Fruits+=(‘Арбуз’) # Также Push
Fruits=( ${Fruits[@]/Ap*/} ) # Удалить по совпадению с regex
unset Fruits[2] # Удалить один элемент
Fruits=("${Fruits[@]}") # Дублировать
Fruits=("${Fruits[@]}" “${Veggies[@]}”) # Конкатенация
lines=(cat "logfile"
) # Чтение из файла
### Массивы в качестве аргументов
``bash
function extract()
{
local -n myarray=$1
local idx=$2
echo "${myarray[$idx]}"
}
Fruits=('Apple' 'Banana' 'Orange')
извлечь Фрукты 2 # => Апельсин
Словари Bash
Определение
``bash declare -A sounds
``bash
звуки[собака]="лай"
звуки[корова]="му"
звуки[птица]="чирикать"
звуки[волк]="вой"
Работа со словарями
``bash echo ${sounds[dog]} # Звук собаки echo ${sounds[@]} # Все значения echo ${!sounds[@]} # Все ключи echo ${#sounds[@]} # Количество элементов unset sounds[dog] # Удалить собаку
### Итерация
``bash
for val in "${sounds[@]}"; do
echo $val
done
``bash for key in “${!sounds[@]}”; do echo $key done
Условные обозначения Bash
------------
### Целочисленные условия
| Условие | Описание |
|---------------------|---------------------------------------------|
| `[[ NUM -eq NUM ]]` | <yel>Eq</yel>ual |
| `[[ NUM -ne NUM ]]` | <yel>N</yel>ot <yel>e</yel>qual |
| `[[ NUM -lt NUM ]]` | <yel>L</yel>ess <yel>t</yel>han |
| `[[ NUM -le NUM ]]` | <yel>L</yel>ess than or <yel>e</yel>qual |
| `[[ NUM -gt NUM ]]` | <yel>G</yel> больше <yel>t</yel>han |
| `[[ NUM -ge NUM ]]` | <yel>G</yel> больше или <yel>e</yel>равно |
| `(( NUM < NUM ))` | Меньше, чем |
| `(( NUM <= NUM ))` | Меньше или равно |
| `(( NUM > NUM ))` | Больше, чем |
| `(( NUM >= NUM ))` | Больше или равно |
### Строковые условия
| Условие | Описание |
|--------------------|-----------------------------|
| `[[ -z STR ]]` | Пустая строка |
| `[[ -n STR ]]` | <yel>N</yel> не пустая строка |
| `[[ STR == STR ]]` | Равно |
| `[[ STR = STR ]]` | Равно (то же, что и выше) |
| `[[ STR < STR ]]` | Меньше _(ASCII)_ |
| `[[ STR > STR ]]` | Больше _(ASCII)_ |
| `[[ STR != STR ]` | Не равно |
| `[[ STR =~ STR ]]` | Regexp |
### Пример {.row-span-3}
#### Строка
``bash
if [[ -z "$string" ]]; then
echo "Строка пуста"
elif [[ -n "$string" ]]; then
echo "Строка не пуста"
else
echo "Такого не бывает"
fi
Комбинации
``bash if [[ X && Y ]]; then … fi
#### Equal
``bash
if [[ "$A" == "$B" ]]; then
...
fi
Regex
``bash if [[ ‘1. abc’ =~ ([a-z]+) ]]; then echo ${BASH_REMATCH[1]} fi
#### Меньше
``bash
if (( $a < $b )); then
echo "$a меньше, чем $b"
fi
Exists
``bash if [[ -e “file.txt” ]]; then echo “файл существует” fi
### Условия файла {.row-span-2}
| Условие | Описание |
|-------------------|----------------------------------------|
| `[[ -e FILE ]]` | <yel>E</yel>xists |
| `[[ -d FILE ]` | <yel>D</yel>irectory |
| `[[ -f FILE ]]` | <yel>F</yel>ile |
| `[[ -h FILE ]]` | Symlink |
| | `[[ -s FILE ]]` | Размер > 0 байт |
| `[[ -r FILE ]]` | <yel>R</yel>eadable |
| `[[ -w FILE ]` | <yel>W</yel>ritable |
| `[[ -x FILE ]]` | Исполняемый |
| `[[ f1 -nt f2 ]` | f1 <yel>n</yel>ewer <yel>t</yel>han f2 |
| `[[ f1 -ot f2 ]` | f2 <yel>o</yel>lder <yel>t</yel>han f1 |
| `[[ f1 -ef f2 ]]` | Те же файлы |
### Дополнительные условия
| Условие | Описание |
|----------------------|----------------------|
| `[[ -o noclobber ]]` | Если OPTION включен |
| `[[ ! EXPR ]]` | Не |
| `[[ X && Y ]]` | И |
| `[[ X || Y ]]` | Или |
### логическое и, или
``bash
if [ "$1" = 'y' -a $2 -gt 0 ]; then
echo "yes"
fi
if [ "$1" = 'n' -o $2 -lt 0 ]; then
echo "no"
fi
Циклы Bash
Базовый цикл for
``bash for i in /etc/rc.*; do echo $i done
### C-подобный цикл for
``bash
for ((i = 0 ; i < 100 ; i++)); do
echo $i
done
Диапазоны
``bash for i in {1..5}; do echo “Добро пожаловать $i” done
#### С размером шага
``bash
for i in {5..50..5}; do
echo "Добро пожаловать $i"
done
Автоинкремент
``bash i=1 while [[ $i -lt 4 ]]; do echo “Число: $i” ((i++)) done
### Автоматический декремент
```bash
i=3
while [[ $i -gt 0 ]]; do
echo "Число: $i"
((i--))
done
Продолжение
for number in $(seq 1 3); do
if [[ $number == 2 ]]; then
продолжить;
fi
echo "$number"
done
Break
``bash for number in $(seq 1 3); do if [[ $number == 2 ]]; then # Пропустить всю оставшуюся часть цикла. break; fi # В результате будет выведено только 1 echo “$number” done
### До
```bash
count=0
until [ $count -gt 10 ]; do
echo "$count"
((count++))
done
Forever
``bash while true; do # здесь находится некоторый код. done
### Forever (сокращение)
``bash
while :; do
# здесь находится некоторый код.
done
Чтение строк
``bash cat file.txt | while read line; do echo $line done
Функции Bash
---------
### Определение функций
``bash
myfunc() {
echo "hello $1"
}
``bash
То же, что и выше (альтернативный синтаксис)
function myfunc() { echo “hello $1” }
``bash
myfunc "John"
Возврат значений
``bash myfunc() { local myresult=‘некоторое значение’ echo $myresult }
``bash
result="$(myfunc)"
Возбуждение ошибок
``bash myfunc() { return 1 }
``bash
if myfunc; then
echo "success"
else
echo "failure"
fi
Опции Bash
Опции
``bash
Избегать наложения файлов
(echo “hi” > foo)
set -o noclobber
Используется для выхода при ошибке
избегая каскадных ошибок
set -o errexit
Выявляет скрытые сбои
set -o pipefail
Выявляет незаданные переменные
set -o nounset
### Глобальные опции
``bash
# Несоответствующие глобусы удаляются
# ('*.foo' => '')
shopt -s nullglob
# Несовпадающие глобусы выбрасывают ошибки
shopt -s failglob
# Нечувствительные к регистру глобусы
shopt -s nocaseglob
# Wildcards match dotfiles
# ("*.sh" => ".foo.sh")
shopt -s dotglob
# Разрешить ** для рекурсивных совпадений
# ('lib/**/*.rb' => 'lib/a/b/c.rb')
shopt -s globstar
История Bash
Команды
Команда | Описание |
---|---|
history |
Показать историю |
sudo !!! |
Выполнить предыдущую команду с помощью sudo |
shopt -s histverify |
Не выполнять расширенный результат немедленно |
Расширения
Выражение | Описание |
---|---|
!$ |
Развернуть последний параметр последней команды |
!* |
Развернуть все параметры последней команды |
!-n |
Развернуть n -ю последнюю команду |
!n |
Развернуть n -ю команду в истории |
!<команда> |
Раскрыть последний вызов команды <команда> |
Операции
Код | Код | Описание |
|———————-|———————————————————————–|
| !!
| Выполнить последнюю команду еще раз | |
| !!!:s/<FROM>/<TO>/
| Заменить первое вхождение <FROM>
на <TO>
в последней команде |
| !!:gs/<FROM>/<TO>/
| Заменить все вхождения <FROM>
на <TO>
в последней команде |
| !$:t
| Расширить только базовое имя из последнего параметра последней команды |
| !$:h
| Расширять только директорию из последнего параметра последней команды |
!!!
и !$
могут быть заменены любым допустимым расширением.
Ломтики
Код | Описание |
---|---|
!!!:n |
Развернуть только n -ю лексему из последней команды (команда - 0 ; первый аргумент - 1 ) |
!^ |
Развернуть первый аргумент из последней команды |
!$ |
Развернуть последнюю лексему из последней команды |
!!:n-m |
|
!!!:n-$ |
Развернуть n -ый токен до последнего из последней команды |
!!!
может быть заменено любым допустимым расширением, например, !cat
, !-2
, !42
и т.д.
Разное
Числовые вычисления
``bash $((a + 200)) # Прибавить 200 к $a
``bash
$(($RANDOM%200)) # Случайное число 0..199
Под-оболочки
``bash (cd somedir; echo “I’m now in $PWD”) pwd # все еще в первой директории
### Проверка команд
``bash
command -V cd
#=> "cd - это функция/алиас/что угодно"
Перенаправление
``bash python hello.py > output.txt # stdout to (file) python hello.py » output.txt # stdout to (file), append python hello.py 2> error.log # stderr в (файл) python hello.py 2>&1 # stderr в stdout python hello.py 2>/dev/null # stderr в (null) python hello.py &>/dev/null # stdout и stderr в (null)
``bash
python hello.py < foo.txt # передать foo.txt на stdin для python
Источник относительный
``bash source “${0%/*}/../share/foo.sh”
### Каталог скрипта
``bash
DIR="${0%/*}"
Case/switch
``bash case “$1” in start | up) vagrant up ;;
*)
echo "Usage: $0 {start|stop|ssh}"
;;
esac
### Отлавливать ошибки {.col-span-2}
``bash
trap 'echo Error at about $LINENO' ERR
или
``bash traperr() { echo “ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}” }
set -o errtrace trap traperr ERR
### printf
``bash
printf "Hello %s, I'm %s" Sven Olga
#=> "Hello Sven, I'm Olga
printf "1 + 1 = %d" 2
#=> "1 + 1 = 2"
printf "Print a float: %f" 2
#=> "Print a float: 2.000000"
Получение опций
``bash while [[ “$1” =~ ^- && !"$1" == “–” ]]; do case $1 in -V | –version ) echo $version exit ;; -s | –string ) shift; string=$1 ;; -f | –flag ) flag=1 ;; esac; shift; done if [[ “$1” == ‘–’ ]]; then shift; fi
### Проверка результата выполнения команды {.col-span-2}
``bash
if ping -c 1 google.com; then
echo "Похоже, что у вас есть рабочее подключение к Интернету"
fi
Специальные переменные
Выражение | Описание |
---|---|
$? |
Статус выхода из последней задачи |
$! |
PID последней фоновой задачи |
$$ |
PID оболочки |
$0 |
Имя файла сценария оболочки |
См. раздел Специальные параметры.
Проверка Grep
``bash if grep -q ‘foo’ ~/.bash_history; then echo “Похоже, что в прошлом вы набирали ‘foo’” fi
### Обратные косые черты {.row-span-2}
-
- \!
- \"
- \#
- \&
- \'
- \(
- \)
- \,
- \;
- \<
- \>
- \[
- \|
- \\
- \]
- \^
- \{
- \}
- \`
- \$
- \*
- \?
{.cols-4 .marker-none}
Экранируйте эти специальные символы с помощью `\`.
### Heredoc
``sh
cat <<END
здравствуй мир
END
Переход в предыдущий каталог
``bash pwd # /home/user/foo cd bar/ pwd # /home/user/foo/bar cd - pwd # /home/user/foo
### Чтение входных данных
``bash
echo -n "Proceed? [y/n]: "
прочитать ans
echo $ans
``bash read -n 1 ans # Только один символ
### Условное выполнение
``bash
git commit && git push
git commit || echo "Commit failed"
Строгий режим
``bash set -euo pipefail IFS=$’\n\t’
См: [Неофициальный строгий режим bash](http://redsymbol.net/articles/unofficial-bash-strict-mode/)
### Необязательные аргументы
``bash
args=("$@")
args+=(foo)
args+=(bar)
echo "${args[@]}"
Поместите аргументы в массив, а затем добавьте
Также смотрите
- Devhints (devhints.io)
- Bash-hackers wiki (bash-hackers.org)
- Shell vars (bash-hackers.org)
- Learn bash in y minutes (learnxinyminutes.com)
- Bash Guide (mywiki.wooledge.org)
- ShellCheck (shellcheck.net)
- shell - Standard Shell (devmanual.gentoo.org)