Bash.im
- 1 year ago
- 0
- 0
Bash (от англ. B ourne a gain sh ell , каламбур «Born again» shell — «возрождённый» shell) — усовершенствованная и модернизированная вариация командной оболочки Bourne shell . Одна из наиболее популярных современных разновидностей командной оболочки UNIX . Особенно популярна в среде Linux , где она часто используется в качестве предустановленной командной оболочки.
Представляет собой командный процессор, работающий, как правило, в интерактивном режиме в текстовом окне. Bash также может читать команды из файла, который называется скриптом (или сценарием ). Как и все Unix-оболочки, он поддерживает автодополнение имён файлов и каталогов, подстановку вывода результата команд, переменные, контроль над порядком выполнения, операторы ветвления и цикла. Ключевые слова, синтаксис и другие основные особенности языка были заимствованы из sh . Другие функции, например, история, были скопированы из csh и ksh . Bash в основном соответствует стандарту POSIX , но с рядом расширений .
Название «bash» является акронимом от англ. Bourne-again-shell («ещё-одна-командная-оболочка-Борна») и представляет собой игру слов: Bourne-shell — одна из популярных разновидностей командной оболочки для UNIX (sh), автором которой является Стивен Борн ( 1978 ), усовершенствована в 1987 году Брайаном Фоксом . Фамилия Bourne (Борн) перекликается с английским словом born , означающим «родившийся», отсюда: рождённая-вновь-командная оболочка.
В сентябре 2014 года в bash была обнаружена широко эксплуатируемая уязвимость Bashdoor .
Подавляющее большинство важных скриптов командного процессора Bourne может выполняться без изменения в bash, за исключением тех, которые ссылаются на специальные переменные Bourne или используют встроенные команды Bourne. Синтаксис команд Bash включает идеи, заимствованные у Korn shell (
ksh
) и C shell (
csh
), такие как редактирование командной строки, история команд, стек каталогов, переменные
$RANDOM
и
$PPID
, синтаксис замены команды
$(…)
. Когда Bash используется как интерактивный командный процессор, он поддерживает автозавершение имён программ, файлов, переменных и т. п. с помощью клавиши
Tab ↹
.
Интерпретатор bash имеет множество встроенных команд, часть из которых имеет аналогичные исполняемые файлы в операционной системе . Однако следует обратить внимание, что чаще всего для встроенных команд отсутствуют man-страницы , а при попытке просмотра справки по встроенной команде на самом деле будет выдаваться справка по исполняемому файлу. Исполняемый файл и встроенная команда могут различаться параметрами. Информация по встроенным командам расписана в справочной странице bash:
man bash
Ввод-вывод | |
---|---|
echo
|
выводит выражение или содержимое переменной ( stdout ), но имеет ограничения в использовании |
printf
|
команда форматированного вывода, расширенный вариант команды
echo
|
read
|
«читает» значение переменной со стандартного ввода ( stdin ), в интерактивном режиме это клавиатура |
Файловая система | |
cd
|
изменяет текущий каталог |
pwd
|
выводит название текущего рабочего каталога (от англ. print working directory ) |
pushd
|
изменяет текущий каталог с возможностью возврата в обратном порядке |
popd
|
возвращает текущий каталог после
pushd
|
dirs
|
выводит или очищает содержимое стека каталогов, сохранённых через
pushd
|
Действия над переменными | |
let
|
производит арифметические операции над переменными |
eval
|
транслирует список аргументов из списка в команды |
set
|
изменяет значения внутренних переменных скрипта |
|
удаляет переменную |
|
экспортирует переменную, делая её доступной дочерним процессам |
declare
,
typeset
|
задают и/или накладывают ограничения на переменные |
getopts
|
используется для разбора аргументов, передаваемых скрипту из командной строки |
Управление сценарием | |
source
,
.
(точка)
|
запуск указанного сценария |
exit
|
безусловное завершение работы сценария |
exec
|
заменяет текущий процесс новым, запускаемым командой
exec
|
shopt
|
позволяет изменять ключи (опции) оболочки «на лету» |
Команды | |
true
|
возвращает код завершения ноль (успешное завершение) |
false
|
возвращает код завершения, который свидетельствует о неудаче |
type
prog
|
выводит полный путь к prog |
hash
prog
|
запоминает путь к prog |
help
COMMAND
|
выводит краткую справку по использованию внутренней команды COMMAND |
Управление запущенными в командной оболочке задачами | |
jobs
|
показывает список запущенных в командной оболочке задач либо информацию о конкретной задаче по её номеру |
fg
|
переключает поток ввода на текущую задачу (или на определённую задачу, если указан её номер) и продолжает её исполнение |
bg
|
продолжает исполнение текущей приостановленной задачи (или определённых задач, если указаны их номера) в фоновом режиме |
wait
|
ожидает завершения указанных задач |
В простейшем случае
скрипт
— простой список команд, записанный в файл. Командный процессор должен знать, что он должен этот файл обработать, а не просто прочесть его содержимое. Для этого служит специальная конструкция, называемая
shebang
:
#!
. Символ
#
задаёт комментарий, но в данном случае shebang означает, что после этого спецсимвола находится путь к интерпретатору для исполнения сценария.
Синтаксис команд bash — это расширенный синтаксис команд Bourne shell. Окончательная спецификация синтаксиса команд bash есть в Bash Reference Manual, распространяемом проектом GNU .
#!/usr/bin/env bash
echo 'Hello World!'
Этот скрипт содержит только две строки. Первая строка сообщает системе о том, какая программа используется для запуска файла. Вторая строка — это единственное действие, которое выполняется этим скриптом, он собственно печатает «Hello world!» в терминале.
Для того, чтобы скрипт стал исполняемым, могут быть использованы следующие команды:
chmod +rx scriptname # выдача прав на чтение/исполнение любому пользователю
chmod u+rx scriptname # выдача прав на чтение/исполнение только «владельцу» скрипта
Из соображений безопасности путь к текущему каталогу
.
не включён в переменную окружения
$PATH
. Поэтому для запуска скрипта необходимо явно указывать путь к текущему каталогу, в котором находится скрипт:
./scriptname
Кроме того, передать такой файл на исполнение
интерпретатору
Bash можно и явно, используя команду
bash
:
bash scriptname
В этом случае не требуется ни установка прав доступа, ни использование последовательности
#!
в коде.
В bash есть встроенные файловые дескрипторы : 0 (stdin), 1 (stdout), 2 (stderr).
Для операций с этими и пользовательскими дескрипторами существуют специальные символы:
>
(перенаправление вывода),
<
(перенаправление ввода). Символы
&
,
-
могут предварять номер дескриптора; например,
2>&1
— перенаправление дескриптора 2 (stderr) в дескриптор 1 (stdout).
0<filename
или
<filename
|
Перенаправление ввода из файла
filename
|
1>filename
или
>filename
|
Перенаправление вывода в файл «filename». Если отключена опция
noclobber
, то файл перезаписывается поступающими данными
|
1>|filename
или
>|filename
|
Перенаправление вывода в файл «filename», файл перезаписывается поступающими данными |
1>>filename
или
>>filename
|
Перенаправление вывода в файл «filename», данные добавляются в конец файла. При отсутствии файла он создаётся |
2>filename
|
Перенаправление стандартного вывода ошибок в файл «filename» |
2>>filename
|
Перенаправление стандартного вывода ошибок в файл «filename», данные добавляются в конец файла. При отсутствии файла он создаётся |
&>filename
|
Перенаправление вывода и ошибок в файл «filename» |
2>&1
|
Перенаправление вывода ошибок на стандартный вывод |
Bash имеет индивидуальный синтаксис перенаправления, который не поддерживается в Bourne shell. Пример одновременного перенаправления стандартного вывода и стандартных ошибок:
command &> file
Это проще набрать, чем эквивалентную команду в синтаксисе Bourne shell
command > file 2>&1
Поддерживается heredoc-синтаксис :
$a='многострочный'
command <<MYDOC123
$a
текст
$(<$HOME/my_file.txt)
MYDOC123
command <<'PERLCODE'
my $first='Hello';
my $second='world';
say join(', ',$first,$second),'!';
PERLCODE
command <<-'TABSTRIP'
for ((i=0; i<10; i++))
do
echo "$i"
done
TABSTRIP
Начиная с версии 2.05b, bash может перенаправлять стандартный ввод из строки, используя следующий синтаксис « here strings »:
command <<< "string to be read as standard input"
Если строка содержит пробелы, её следует заключить в кавычки или апострофы, либо экранировать пробелы обратной косой чертой.
Будьте внимательны: вводимая с использованием here strings строка содержит неявную последовательность завершения строки: либо 1 дополнительный байт line feed , либо 2 дополнительных байта: carriage return и line feed.
cat -<<<'123' | wc -c
# Результат: 4
cat <(echo -n '123') | wc -c
# Результат: 3
wc -c <<<'123'
# Результат: 4
echo -n 123 | wc -c
# Результат: 3
Начиная с версии 4.1 стало возможным указывать в одной строке терминирующую последовательность символов и, сразу за ней, — скобку. Это может быть полезно для присвоения переменной содержимого here-doc:
var=$( cat -<<'TERMSEQ'
Февраль. Достать чернил и плакать!
Писать о феврале навзрыд,
Пока грохочущая слякоть
Весною чёрною горит.
TERMSEQ)
При этом BASH будет сгенерировано предупреждающее сообщение.
Пример (перенаправление стандартного вывода в файл, запись данных, закрытие файла, сброс stdout):
# make Filedescriptor(FD) 6 a copy of stdout (FD 1)
exec 6>&1
# open file "test.data" for writing
exec 1>test.data
# produce some content
echo "data:data:data"
# close file "test.data"
exec 1>&-
# make stdout a copy of FD 6 (reset stdout)
exec 1>&6
# close FD6
exec 6>&-
Открытие и закрытие файлов:
# open file test.data for reading
exec 6<test.data
# read until end of file
while read -u 6 dta
do
echo "$dta"
done
# close file test.data
exec 6<&-
Захват вывода внешних команд:
# выполнить 'date' и поместить результат в VAR
VAR="$(date)"
echo "$VAR" #выведет дату на момент вызова предыдущей строки
При этом не поддерживаются строки с нуль-символом, заключительные переводы строк пропадают, в отличие от каналов и прочего файлового ввода-вывода .
#!/usr/bin/env bash
T1='foo'
T2='bar'
if [[ $T1 == "$T2" ]]
then
echo 'условие выполняется'
else
echo 'условие не выполняется'
fi
Обратите внимание, что кавычки вокруг левой части необязательны.
#!/usr/bin/env bash
for i in "Номер "{1..10}
do
echo "$i"
done
#!/usr/bin/env bash
COUNTER=0
while [[ $COUNTER -lt 10 ]] # До тех пор, пока условие ИСТИННО (возвращает 0) выполнять тело цикла
do
echo The counter is $COUNTER
let COUNTER=COUNTER+1
done
#!/usr/bin/env bash
i=0
until [[ $i -eq 10 ]] # До тех пор, пока условие ЛОЖНО (возвращает не 0) выполнять тело цикла
do
echo "$i"
i=$(($i+1))
done
#!/usr/bin/env bash
# внутри двойных круглых скобок переменные можно писать в Си-стиле (без $ и разделяя пробелом операторы и операнды)
for (( i = 0; i < 10; i++ ))
do
echo -n "$i; "
done
В bash реализованы только одномерные массивы. Индексами могут быть как целочисленные значения («обычный» массив ), так и строки ( ассоциативный массив , или «хеш»).
Несмотря на унификацию синтаксиса для работы с обычными и ассоциативными массивами, первые не являются разновидностью вторых ни с точки зрения конечного пользователя, ни с точки зрения внутренней логики самого интерпретатора.
Как естественное следствие поддержки «ассоциативных» ключей, в bash существует крайне ограниченная возможность эмуляции многомерных массивов.
Получить значение элемента как индексированного, так и ассоциативного массива можно:
declare -a arrLinear=(11 22 33 44)
declare -A arrAssoc=([city]='London' [index]='420224' )
vi=${arrLinear[3]} # vi=44
va=${arrAssoc['city']} # va='London'
declare -i n=3
vi=${arrLinear[$i]} # vi=44
vi=${arrLinear[i]} # аналогично предыдущему, но без сигила
declare index='city'
va=${arrAssoc[$index]} # va='London', и это правильно
va=${arrAssoc[index]} # va='420224', и это ошибочный результат, если подразумевалось [$index]
va=${arrAssoc['index']} # va='420224'
Получить строку, состоящую из всех элементов массива, разделённых пробелом.
values="${arr[@]}"
Получить строку со всеми индексами или ключами массива, независимо от того, численные они или текстовые:
keys="${!arr[@]}"
Осуществить массовую замену первого вхождения подстроки «MAY» на «MARCH» во всех элементах массива и вернуть строку, составленную из результирующих элементов массива, разделённых пробелом:
values="${arr[@]/MAY/MARCH}"
То же самое, но в каждом элементе массива будут заменены все вхождения подстроки «MAY»:
values="${arr[@]//MAY/MARCH}"
До сих пор не все заявленные в документации возможности правильно работают для массивов. Например:
[ -v 'имя_массива' ]
неправильно срабатывает для пустого массива.
Bash имеет поддержку одномерных массивов. Инициализировать элементы массива можно в виде:
my_array[xx]
. Также можно явно объявить массив в сценарии, с помощью директивы
declare
:
declare -a my_array
Обращаться к отдельным элементам массива можно с помощью фигурных скобок:
"${my_array[xx]}"
.
Инициализировать индексированный массив можно двумя способами:
1)
Array=(element1 element2 element3)
2)
temp_array[0]=element1
temp_array[5]=element
temp_array[9]=elementN
Добавление элементов в конец индексированного массива:
declare -a arrAnimals
arrAnimals=(dog elephant horse cow fox koala turtle)
# Выводим содержимое массива:
echo "${arrAnimals[@]}"
# В конец массива arrAnimals добавляем новый элемент: "pig"
arrAnimals+=(pig)
# И снова показываем содержимое массива:
echo "${arrAnimals[@]}"
Получить первый элемент массива:
echo "${arrAnimals[0]}"
Как индексированные, так и ассоциативные массивы поддерживают так называемые «срезы»:
# Ещё один способ получить первый элемент массива
echo "${arrAnimals[@]:0:1}"
# Вывести 3 элемента массива, начиная со 2-го:
echo "${arrAnimals[@]:2:3}"
Примечание: в случае с ассоциативными массивами порядок следования значений в общем случае будет случайным (определяется используемой хеш-функцией), поэтому операция среза на ассоциативном массиве хотя и допустима, но имеет крайне ограниченную область практического применения.
В массивах с числовыми индексами допустима «обратная» («негативная») адресация, позволяющая получить доступ к элементам, начиная с конца массива:
# Значение последнего элемента массива
echo "${arrAnimals[-1]}"
# Значение предпоследнего элемента массива
echo "${arrAnimals[-2]}"
# ... и т.д.
С помощью встроенной команды
mapfile
(синоним:
readarray
) можно отображать содержимое текстового файла в индексированный массив:
declare -a fileWithLogins
mapfile fileWithLogins </etc/passwd
for ((i=0; i<${#fileWithLogins[@]}; i++))
do
echo "Line #$i: ${fileWithLogins[$i]}"
done
Начиная с версии 4.0 в bash появилась поддержка ассоциативных массивов (так называемых hash-массивов).
Для объявления ассоциативных массивов используется ключ
-A
встроенной команды
declare
:
declare -A hshArray
Как и в случае с индексированными массивами, для заполнения ассоциативных массивов могут использоваться два различных синтаксиса:
1)
TheCapitalOf[Georgia]='Tbilisi'
TheCapitalOf[Australia]='Canberra'
TheCapitalOf[Pakistan]='Islamabad'
2)
TheCapitalOf=([Georgia]='Tbilisi' [Australia]='Canberra' [Pakistan]='Islamabad')
С помощью ассоциативных массивов можно имитировать поддержку многомерных массивов:
declare -A a # объявляет ассоциативный массив 'a'
i=1; j=2 # инициализация нескольких индексов
a[$i,$j]=5 # присвоение значения "5" в ячейку "$i,$j" (т.е. "1,2")
echo ${a[$i,$j]} # вывод хранимых значений из "$i,$j"
К сожалению, в текущих версиях bash скопировать содержимое одного ассоциативного массива в другой простым присваиванием невозможно. Данную проблему можно только обойти, для чего существуют два принципиально разных подхода:
1) Эмулировать объявление второго хеша «с нуля» путём копирования объявления первого хеша:
declare -A hsh1
hsh1=(...)
source <(declare -p hsh1 | sed 's/^declare -A hsh1/declare -A hsh2/')
2) Перебрать все элементы хеша-источника и скопировать их в целевой хеш:
declare -A hsh1 hsh2
hsh1=(...)
for k in "${!hsh1[@]}"
do
hsh2["$k"]="${hsh1["$k"]}"
done
Массивы являются удобным способом передачи динамически сгенерированных аргументов в функции или команды. При этом каждый элемент массива представляет собой отдельный аргумент.
args=( ls -l -a / )
ls "${args[@]}" # ls -l -a /
ls ${args[@]} # ls -l -a /
ls ${args[*]} # ls -l -a /
Однако при подобном использовании массивов следует быть осторожным ввиду особенностей раскрытия массивов при использовании в качестве индексов специальных символов
@
и
*
.
Если массив заключён в кавычки и раскрывается с помощью индекса
@
, то образуется строка из слов, где каждое слово — отдельный элемент массива. Однако если не заключить раскрытие массива в двойные кавычки, то может получиться совсем другой результат: пробелы, входящие в состав элементов массива, становятся разделителями слов.
args=( -l -a '/home/user/Рабочий стол' )
ls "${args[@]}" # просмотр содержимого каталога '/home/user/Рабочий стол'
ls ${args[@]} # ошибка: каталогов '/home/user/Рабочий' и './стол' не существует
Массив с индексом
*
, заключённый в двойные кавычки, раскрывается в одну строку, соединяя все элементы массива через разделители, хранимые в переменной
IFS
. Если не указать двойные кавычки, то массив раскрывается аналогично раскрытию при использовании индекса
@
.
args=( '' usr local bin )
IFS='/' ls "${args[*]}" # просмотр содержимого каталога '/usr/local/bin'
IFS='/' ls ${args[*]} # поочерёдный просмотр содержимого каталогов '.', './usr', './local' и './bin'
При создании массива из содержимого текстовой переменной необходимо учитывать возможное наличие пробелов в тексте. Например, в качестве одного из способов создания массива из строки с перечислением можно рассматривать замену символа-разделителя на пробел. Однако наличие пробелов в разделяемых элементах приведёт к дроблению самих элементов на части.
array=( ${text//,/} ) # неправильно: текст в переменной 'text' мог содержать пробельные символы
IFS=',' array=( $text ) # правильно: раздельтельным символом является запятая.
IFS=',' read -r -a array <<< "$text" # правильно (альтернативный вариант с перенаправлением содержимого переменной 'text' в команду 'read')
К ошибкам может привести создание массива из текста, полученного в качестве вывода команд или из файла, так как не только переводы строк, но также и пробелы с символами табуляции по умолчанию будут считаться разделителями .
array=( "$(ls)" ) # неправильно: пробелы в названии файлов могут разбить имя файла на два элемента массива
IFS=$'\n' array=( "$(ls)" ) # правильно: разделителем будет только перевод строк
mapfile -t array < <(ls) # правильно: альтернативный вариант через встроенную команду mapfile
Конвейер
передаёт вывод предыдущей команды на ввод следующей или на вход командного интерпретатора. Метод часто используется для связывания последовательности команд в единую цепочку. Конвейер обозначается символом
вертикальной черты
|
.
Пример ( grep работает как фильтр для стандартного вывода):
cat filename | grep pattern
Логическое ИЛИ обозначается как
||
. В операциях проверки условий оператор
||
возвращает 0 (success), если один из операндов имеет значение true (ИСТИНА).
Логическое И обозначается как
&&
. В операциях проверки условий оператор
&&
возвращает 0 (success) тогда и только тогда, когда оба операнда имеют значение true (ИСТИНА).
Примечание: Возможная путаница в понимании возникает из-за того, что
команда
true
(и успешное завершение любой команды) завершается с
кодом возврата
0, success (
false
, наоборот, не 0), в то время как
логическое значение
true/false — отлично от нуля/равно нулю.
Примеры:
if false; then echo "successfully"; else echo "unsuccessfully"; fi
unsuccessfully
let "a=(( 1 && 0 && 123))"; echo $?; echo $a
1 # Код завершения команды (нулевой результат вычисления арифметического выражения)
0 # Значение переменной "a", результат логической операции
if (( 1 && 0 && 123)); then echo "true"; else echo "false"; fi
false
let "a=(( 1 && 123 && -345 ))"; echo $?; echo $a
0 # Код завершения команды
1 # Значение переменной "a", результат логической операции
if (( 1 && 123 && -345 )); then echo "true"; else echo "false"; fi
true
false && echo "Успешное завершение" || echo "Неуспешное завершение"
Неуспешное завершение
Bash может выполнять целочисленные вычисления внутри процесса, используя команду
((…))
и синтаксис переменной
$((…))
, как показано ниже:
VAR=55 # Устанавливаем переменную VAR, равной 55
((VAR = VAR + 1)) # Добавляем единицу к переменной VAR. Обратите внимание на отсутствие знака '$'
((VAR+=1)) # Сокращённая форма записи инкремента
((++VAR)) # Другой способ увеличения VAR на единицу. Выполняет префиксный инкремент
((VAR++)) # Другой способ увеличения VAR на единицу. Выполняет постфиксный инкремент
echo $((VAR * 22)) # Умножаем VAR на 22 и передаем результат команде
echo $[VAR * 22] # Устаревший способ сделать то же
((VAR<<3)) # Побитовый сдвиг влево (то же, что VAR*8)
((VAR>>3)) # Побитовый сдвиг вправо (то же, что VAR/8)
Команда
((…))
также может использоваться в условных утверждениях, так как её исходный параметр — это 0 или 1, которые могут интерпретироваться как true или false:
if ((VAR == Y * 3 + X * 2))
then
echo Yes
fi
((Z > 23)) && echo Yes
Команда
((…))
поддерживает следующие операторы сравнения:
==
!=
>
<
>=
<=
.
Bash не поддерживает вычисления внутри процесса с числами с плавающей точкой. Только командные процессоры Unix Korn shell (версия 1993 года ) и zsh (начиная с версии 4.0) поддерживают эту возможность.
Список математических операций:
+
,
-
,
*
,
/
,
**
(возведение в степень),
%
(деление по модулю, остаток от деления),
let
— позволяет использовать сокращения арифметических команд (сокращая количество используемых переменных; например:
a += b
эквивалентно
a = a + b
и т. п.).
Аргументы:
$$
|
pid текущего shell (самого процесса-сценария) |
$!
|
pid последнего процесса в фоновом режиме |
$?
|
код возврата последнего процесса (функции или скрипта) |
$
x
|
где
x
— номер параметра, переданного скрипту (
$1
,
$2
и т. д.,
$0
— последний запущенный скрипт)
|
$#
|
количество аргументов командной строки |
$*
|
все аргументы в виде одной строки (слова) |
$@
|
то же самое, что и
$*
, но при этом каждый
параметр представлен как отдельная строка (слово)
|
$-
|
список флагов, переданных сценарию |
$_
|
содержит последний аргумент предыдущей команды |
Встроенные переменные:
$BASH
|
путь к исполняемому файлу bash |
$BASHPID
|
PID текущего bash * (см. Примечание) |
$BASH_VERSINFO[n]
|
массив, состоящий из 6 элементов, содержащий информацию о версии bash |
$BASH_VERSION
|
версия Bash, установленного в системе |
$DIRSTACK
|
содержимое вершины стека каталогов |
$EDITOR
|
заданный по умолчанию редактор |
$EUID
|
«эффективный» идентификационный номер пользователя (Effective User ID) |
$FUNCNAME
|
имя текущей функции |
$GLOBIGNORE
|
перечень шаблонных символов, которые будут проигнорированы при выполнении подстановки имён файлов (globbing) |
$GROUPS
|
группы, к которым принадлежит текущий пользователь |
$HOME
|
домашний каталог пользователя |
$HOSTNAME
|
сетевое имя хоста |
$HOSTTYPE
|
тип машины (идентифицирует аппаратную архитектуру) |
$IFS
|
разделитель полей во вводимой строке |
$LC_COLLATE
|
задаёт порядок сортировки символов, в операциях подстановки имён файлов и в поиске по шаблону |
$LC_CTYPE
|
определяет кодировку символов |
$LINENO
|
Номер строки исполняемого сценария |
$MACHTYPE
|
аппаратная архитектура |
$OLDPWD
|
прежний рабочий каталог |
$OSTYPE
|
тип операционной системы |
$PATH
|
путь поиска (включает в себя каталоги
/usr/bin/
,
/usr/X11R6/bin/
,
/usr/local/bin
и т. д.)
|
$PIPESTATUS
|
Код возврата канала (конвейера) |
$PPID
|
PID (идентификатор) родительского процесса |
$PS1
|
приглашение командной строки |
$PS2
|
вторичное приглашение командной строки, выводится тогда, когда от пользователя ожидается дополнительный ввод. Обычно отображается как «>» |
$PS3
|
третичное приглашение, выводится, когда пользователь должен сделать выбор в операторе
select
|
$PS4
|
приглашение четвёртого уровня, выводится (в изменённом виде) в начале каждой строки отладочного вывода тогда, когда сценарий вызывается с ключом
-x
. Обычно отображается как «+», «++» и т. д.
|
$PWD
|
рабочий (текущий) каталог |
$REPLY
|
переменная по умолчанию, куда записывается ввод пользователя, выполненный с помощью команды
read
|
$SECONDS
|
время работы сценария (в секундах) |
$SHELLOPTS
|
список допустимых опций интерпретатора (доступна только для чтения) |
$SHLVL
|
уровень вложенности shell |
Пример:
$ echo $(echo $BASHPID $$) $$ $BASHPID 25680 16920 16920 16920 # | | | | # | | | -- $BASHPID outside of the subshell # | | -- $$ outside of the subshell # | -- $$ inside of the subshell # -- $BASHPID inside of the subshell
Bash 3.0 поддерживает встроенные регулярные выражения с синтаксисом, подобным синтаксису Perl :
[[string =~ regex]]
Синтаксис регулярных выражений задокументирован на страницах документации man 7 regex. Статус выхода устанавливается в 0, если регулярное выражение совпало со строкой, и 1, если нет. Значение подвыражения, заключённого в скобки, можно получить
через переменную
${BASH_REMATCH[@]}
, например:
REGEXP='foo(bar)bl(.*)'
if [["abcfoobarbletch" =~ $REGEXP]]
then
echo "Регулярное выражение совпало со строкой!"
echo "$BASH_REMATCH" # выводит: foobarbletch
echo "${BASH_REMATCH[1]}" # выводит: bar
echo "${BASH_REMATCH[2]}" # выводит: etch
fi
Встроенные регулярные выражения обычно работают быстрее, чем выполнение внешней команды grep, потому что соответствующее регулярное выражение выполняется в рамках процесса bash. Если регулярное выражение или строка содержат пробелы или метасимволы (такие как
*
или
?
), их следует взять в кавычки. Рекомендуется использовать переменную для хранения регулярного выражения, как в вышеприведённом примере, для избежания проблем с экранированием специальных символов. Можно использовать вывод bash с опцией
-x
для проверки, как именно bash воспринимает ваше регулярное выражение.
Возможность расширения скобок заимствована у csh . Она позволяет произвольной строке быть сформированной с использованием похожей техники, как это делается с названиями файлов. Однако в bash сгенерированные строки не обязаны быть именами файлов. Результат каждого расширения строки не сортируется, сохраняется порядок слева направо:
# Это особенность присущая bash
echo a{p,c,d,b}e # ape ace ade abe
Не следует использовать эту особенность, если скрипт планируется портировать, потому что в традиционных скриптах расширение строки не будет действовать:
# Традиционная оболочка не даёт тот же результат
echo a{p,c,d,b}e # a{p,c,d,b}e
Когда используется расширение скобок в сочетании с символами подстановки, скобки раскрываются первыми, а затем результат обрабатывается в обычном режиме. Таким образом, список JPEG- и PNG-изображений в текущем каталоге может быть получен так:
ls *.{jpg,jpeg,png} # скобки раскрываются до *.jpg *.jpeg *.png, после чего выполняется поиск по маскам
clear
).
Bash при запуске вызывает команды из множества различных скриптов.
Когда bash вызывается как
интерактивная
оболочка
входа в систему, первым делом он читает и вызывает команды из файла
/etc/profile
, если этот файл существует. После чтения этого файла он смотрит следующие файлы в следующем порядке:
~/.bash_profile
,
~/.bash_login
и
~/.profile
, читает и вызывает команды из первого, который существует и доступен для чтения. При выходе bash читает и выполняет команды из файла
~/.bash_logout
.
Когда запускается интерактивная оболочка, но не для входа в систему, bash читает и исполняет команды из файлов
/etc/bash.bashrc
и
~/.bashrc
, если они существуют. Это может быть отменено опцией
-norc
. Опция
-rcfile file
заставит bash использовать команды из файла
file
вместо
/etc/bash.bashrc
и
~/.bashrc
.
Первой строкой скрипта должна быть запись
#!/bin/bash
, если известен абсолютный путь к исполняемому файлу, либо
#!/usr/bin/env bash
для автоматического определения пути к исполняемому файлу через команду
env
с помощью переменной окружения
PATH
.
Скрипты оболочек, написанные со специфическими для bash особенностями, не будут работать на системах, где используется Bourne shell (sh) или один из его аналогов, если bash не был установлен в качестве дополнительной оболочки. Эта проблема стала особенно важной, когда Ubuntu начал с октября 2006 года поставлять Debian Almquist shell (dash) как скриптовую оболочку по умолчанию, что привело к неработоспособности многочисленных скриптов.
Существует множество программ, позволяющих создавать графический интерфейс к bash-скриптам.
-n
(в отличие от
printf
-- '%s\n' "${переменная}"
), так как
-n
интерпретируется как параметр команды
echo
.
$[…]
.