BASH

Заметки из книги "BASH. Карманный справочник системного администратора"

bash-huyash

Команды оболочки bash можно выполнять с терминала, из файла (когда первым аргументом передано имя файла) или можно подавать баш скрипты на вход команде bash:

macbook:~ vandud$ echo "echo govno" | bash
govno
macbook:~ vandud$ echo "echo govno" | bash -s
govno

Ключ -i запустит оболочку и покажет приглашение:

macbook:~ vandud$ bash -i

The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
bash-3.2$ echo "echo 'mocha i govno'" | bash -s
mocha i govno
bash-3.2$ 

Исходные оболочки читают содержимое файлов /etc/profile и -/.profile, а обычные оболочки - содержимое переменной окружения $ENV, если она установлена

Исходная оболочка это та которая служит для входа в систему


--init-file/--rcfile - переопределить ~/.bashrc



macbook:test vandud$ cat test
echo "govno"
macbook:test vandud$ ls -l test
-rw-r--r--  1 vandud  wheel  13 Feb 19 07:22 test
macbook:test vandud$ ./test
-bash: ./test: Permission denied
macbook:test vandud$ bash test
govno

Код завершения команды доступен в переменной $?
Внутренние команды оболочки передают этот код непосредственно оболочке, а внешние команды передают его операционной системе
Значение кода завершения может находиться в диапазоне от 0 до 255
Preview_2021-02-19-07-29-58.png


Инит файлы читаются в следующем порядке

  1. /etc/profile
  2. Первый найденный из ~/.bash_profile, ~/.bash_login или ~/.profile
  3. ~/.bashrc читается неисходными оболочками, но не читается если оболочка запущена как sh или с параметром --posix (в этих двух случаях читается $ENV)

При выходе из интерактивной оболочки выполняется ~/.bash_logout (при наличии)


Интересный момент про ссылки

macbook:test vandud$ cat test
echo $0
macbook:test vandud$ ls -lh
total 8
-rwxr--r--  1 vandud  wheel     8B Feb 19 10:22 test
lrwxr-xr-x  1 vandud  wheel     4B Feb 19 10:22 test2 -> test
macbook:test vandud$ ./test
./test
macbook:test vandud$ ./test2
./test2

Существует сокращение для получения хомяка пользователя

vandud@macbook test % grep logd /etc/passwd
_logd:*:272:272:Log Daemon:/var/db/diagnostics:/usr/bin/false
vandud@macbook test % echo ~_logd
/var/db/diagnostics

Немного про глоббинг
Базовые штуки

Для этих нужно чтоб был включен параметр extglob (в bash он ставится через shopt -s extglob, в zsh через setopt)

Шаблонов может быть много, тогда их нужно разделять пайпом


Классы символов (для них тоже требуется extglob)
Указываются в [[:<class>:]]


Скрипты читаются построчно
Каждая строка сначала читается, потом проверяется на синтаксис, а потом уже выполняется
Поэтому, например, нельзя определить алиас и вызвать его в одной строке
Нужно учитывать аналогичные примеру операции


Подстановки (выше) и раскрытие скобок отличаются
При раскрытии скобок образуется текст, который не обязательно должен совпадать с уже существующими файлами

Есть два варианта раскрытия скобок

vandud@macbook test % echo head{A,B,C}tail
headAtail headBtail headCtail
vandud@macbook test % echo head{A..C}tail
headAtail headBtail headCtail

vandud@macbook test % echo head{1..5..2}tail
head1tail head3tail head5tail

В числовом выражении предел start может предваряться нулями

vandud@macbook test % echo head{001..5..2}tail
head001tail head003tail head005tail

vandud@macbook test % echo head{01..005..2}tail
head01tail head03tail head05tail

По длине числа start будут выровняны раскрытые числа

vandud@macbook test % echo {0..10..5}
0 5 10
vandud@macbook test % echo {00..10..5}
00 05 10
vandud@macbook test % echo {000..10..5}
000 005 010
vandud@macbook test % echo {0000..10..5}
0000 0005 0010

Скобки могут быть вложенными

vandud@macbook test % echo {a,b,{1..4}}
a b 1 2 3 4

vandud@macbook test % echo {a..b..{1..4}}
{a..b..1} {a..b..2} {a..b..3} {a..b..4}

vandud@macbook test % echo {a..b..{1..5..2}}
{a..b..1} {a..b..3} {a..b..5}

Скобки должны быть без кавычек, иначе баш не распарсит

Подстановки команд будут проигнорированы при раскрытии скобок (но у меня в zsh работает, в баше не смог)

vandud@macbook test % echo {1..10..$(echo 3)} 
1 4 7 10
vandud@macbook test % echo {1..10..`echo 3`} 
1 4 7 10

vandud@macbook test % echo hi{DD,BB,CC,AA}bitch
hiDDbitch hiBBbitch hiCCbitch hiAAbitch

vandud@macbook test % ls LKz{QQ,Qt}e0f         
LKzQQe0f	LKzQte0f

В качестве элемента внутри скобок может быть и пустота

vandud@macbook test % ls zhopa*  
zhopa
vandud@macbook test % mv zhopa{,_s_gavnoy}
vandud@macbook test % ls zhopa*           
zhopa_s_gavnoy

Управляющие последовательности распознаются и интерпретируются в след. контекстах

Terminal_2021-02-19-17-09-25.png


В кавычках отменяется спец. значение символов, например скобок, стрелок, итд
Teampaper-Snap_2021-02-19-17-29-21.png
Teampaper-Snap_2021-02-19-17-29-35.png


Внутри двойных кавычек действует доллар и тик

Внутри одинарных кавычек все становится обычным текстом

\ - используется для экранирования



cmd < filename

vandud@macbook test % cat zhopa_s_gavnoy | cat
asonetuhaoesntuhsanoethustaoehustnaoehusnaeohus

vandud@macbook test % cat < zhopa_s_gavnoy                                                 
asonetuhaoesntuhsanoethustaoehustnaoehusnaeohus

vandud@macbook test % cat zhopa_s_gavnoy | grep -o 'aso'
aso

vandud@macbook test % grep -o 'aso' < zhopa_s_gavnoy                                       
aso

То же самое что и выше, только данные берутся не из файла а из текста
cmd << text

vandud@macbook test % cat <<< "niga mazafaka bitch"
niga mazafaka bitch
vandud@macbook test % echo "niga mazafaka bitch" | cat
niga mazafaka bitch

cmd << EOF

vandud@macbook test % cat << ZHOPA | grep -i niga
pipe heredoc> niga1
pipe heredoc> niiga2
pipe heredoc> zhopa
pipe heredoc> ZHOPA
niga1

>| - позволяет перезаписать файл даже если включен параметр noclobber

bash-3.2$ set -o | grep clobber 
noclobber      	off

bash-3.2$ cat test
govno
bash-3.2$ echo "zhopa" > test
bash-3.2$ cat test
zhopa

bash-3.2$ set -o noclobber
bash-3.2$ set -o | grep clobber
noclobber      	on

bash-3.2$ cat test
zhopa
bash-3.2$ echo "govno" > test
bash: test: cannot overwrite existing file
bash-3.2$ cat test
zhopa
bash-3.2$ echo "govno" >| test # SUCCESS
bash-3.2$ cat test
govno
bash-3.2$ 

О параметрах
У оболочки есть разные параметры
Один из них упоминался ранее (extglob)
Для просмотра и установки этих параметров можно использовать команду set или shopt

Существует сразу две команды потому что set (и параметры с которыми можно взаимодействовать через него) унаследовался вместе с bourne-style (от sh), а shopt появился в bash. Поэтому некоторые параметры могут быть не видны в одном и видны в другом

Посмотреть текущее состояние можно так

set -o
shopt

Активировать так

set -o noclobber # enable
set +o noclobber # disable

shopt -s extglob # enable
shopt -u extglob # disable

Параметров всяких целая куча, тут парочку показал для примера


Перенаправление вывода по дескриптору

Пробел между стрелкой и ФД не нужен


stderr в stdout

root@mars:/var/tmp/test# nginx 2>&1 | tee nginx.out
root@mars:/var/tmp/test# nginx |& tee nginx.out 

bash doc

http://www.gnu.org/software/bash/manual/bash.html

1 Introduction

1.1 Что такое Bash

Bash это шелл, или командный интерпретатор для операционных систем GNU. Имя является акронимом от 'Bourne-Again SHell', игрой слов на Стивена Борна, автора прямого предка текущего Unix шелла - sh, который появился в Седьмом Издании Bell Labs Research версии Unix.

Bash хорошо совместим с sh и объединяет в себе полезные фишки из Korn shell ksh и C shell csh. Он направлен на то чтобы быть совместимой имплементацией 'IEEE POSIX Shell and Tools' которая является частью спецификации POSIX. Он предлагает улучшения функционала поверх sh сразу для интерактивности и использования в программировании.

Операционные системы GNU предоставляют другие шеллы, включая csh, Bash является шеллом по умолчанию. Как и другое ПО GNU, Bash полностью портабельный. На данный момент он запускается на почти каждом Unix'e и нескольких других ОС - существуют порты для MS-DOS, OS/2 и Windows которые поддерживаются независимыми разработчиками.


1.2 Что такое Шелл

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

Unix шелл одновременно и интерпретатор команд и язык программирования. Как интерпретатор команд шелл предоставляет пользовательский интерфейс к богатому набору GNU утилит. Как язык программирования он позволяет комбинировать эти утилиты. Можно создавать файлы с командами и делать их командами. Эти новые команды могут иметь такой же статус как и системные команды в таких директориях как /bin, позволяя пользователям или группам создавать кастомные условия для автоматизации их повседневных задач.

Шеллы могут использоваться интерактивно или неинтерактивно. В интерактивном режиме они позволяют делать ввод с клавиатуры. В неинтерактивном шеллы выполняют команды читая их из файла.

Шелл позволяет выполнять GNU команды синхронно и асинхронно. Шелл ждет окончания выполнения синхронной команды прежде чем разрешить вводить новые команды; асинхронные команды продолжают выполнение в параллели с шеллом пока он читает и выполняет дополнительные команды. Перенаправления позволяют тонко контролировать ввод и вывод команд. Кроме того шелл позволяет контролировать окружения команд.

Шеллы также предоставляют небольшой набор встроенных команд (builtins) давая функциональность которую невозможно или неудобно получить через выделенные утилиты. Например, cd, break, continue и exec не могут быть выполнены снаружи шелла, потому что они направлены на управление самим шеллом. Встроенные history, getopts, kill или pwd могут быть имплементированы в выделенных утилитах, но их гораздо удобнее использовать как встроенные команды. Все встроенные команды будут описаны ниже.

Хоть выполнение команд это и суть оболочки, основная мощь (и сложность) связана с внутренним языком программирования. Как и любой высокоуровневый язык, шелл предоставляет переменные, конструкции для конроля над потоком выполнения, кавычки и функции.

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


2 Определения

Эти определения используются во всей оставшейся части этого манула.


3 Базовые Функции Оболочки

Bash это акроним для 'Bourne-Again SHell'. Шелл Борна это традиционный Unix шелл написанный Стивеном Борном. Все встроенные команды Шелла Борна доступны в Bash, Правила оценки и цитирования взяты из спецификации POSIX для 'стандартной' оболочки Unix.

Эта глава кратко резюмирует 'строительные блоки' шелла: команды, структуры управления, функции шелла, параметры шелла, расширения, перенаправления, которые являются способом прямого ввода и вывода из и в именованный файл, и то как шелл выполняет команды.

3.1 Синтакс Шелла

Когда шелл читает ввод, он делает это через последовательность операций. Если ввод показывает что начинается комментарий, то шелл игнорирует символ комментария ('#') и остальную строку.

Иначе, грубо говоря, шелл читает инпут и разделяет его на слова и операторы, применяя правила для выбора того какие значения назначать различным словам и символам.

Затем шелл парсит эти токены в команды и другие конструкции, убирает особый смысл у одних слов и символов, расширяет другие, перенаправляет ввод и вывод как надо, выполняет указанные команды, ждет код ответа этих команд и делает его доступным для последующей инспекции или обработки.


3.1.1 Работа Шелла

Далее краткое описание работы шелла когда он читает и выполняет команду. Обычно шелл делает следующее:

  1. Читает ввод из файла (см. '3.8 Шелл скрипты'), из строки которая передана аргументом в -c опцию вызова (см. '6.1 Вызов Bash') или из пользовательского терминала
  2. Разделяет ввод на слова и операторы, используя правила кавычек описанные в '3.1.2 Кавычинг'. Эти токены выделяются с помощью metacharacters. Разворачивание алиасов выполняется на этом этапе (см. '6.6 Алиасы')
  3. Парсинг токенов в простые и сложные команды (см. '3.2 Команды Шелла')
  4. Выполнение различных расширений (см. '3.5 Шелл Расширения'), разбиение расширенных токенов в список имен файлов (см. '3.5.8 Расширение Имен Файлов'), команд и аргументов
  5. Выполнение необходимых перенаправлений (см. '3.6 Перенаправления') и удаление операторов перенаправления и их операндов из списка аргументов
  6. Выполнение команд (см. '3.7 Выполнение Команд')
  7. Опциональное ожидание завершения команд и сбор их статускодов (см. '3.7.5 Статускод')

3.1.2 Кавычинг

Кавычинг используется для удаления специальных значений определенных символов и слов в шелле. Кавычинг может быть использован для отключения специальной обработки для специльных символов, для предотвращения от распознавания зарезервированых слов как таковых, и для предотвращения разворачивания параметров.

Каждый из метасимволов (см. '2 Определения') имеет специальное значение и поэтому должен быть закавычен если он должен отображать себя. Когда используется символ разворачивания из истории команд, обычно это '!', он должен быть закавычен для предотвращения разворачивания.

Имеется три кавычинговых механизма: escape character, одиночные кавычки, двойные кавычки.


3.1.2.1 Эскейп Символы

Незакавыченный бэкслэш '\' это Bash escape символ. Он отображает буквальное значение следующего за ним символа, символ новой строки - исключение. Если встречается пара \newline в которой бэкслэш незакавычен, то символ новой строки рассматривается как продолжение строки (он удаляется из введенной строки и по факту игнорируется).

root@mars:~# echo niga\ #enter
>pidor #enter
nigapidor

3.1.2.2 Одиночные Кавычки

Символы заключенные в одиночные кавычки (" ' ") отоборажают буквальное значение каждого символа в кавычках. Одиночная кавычка не может быть между одиночными кавычками, даже если она заэкранирована бэкслэшем.

root@mars:~# echo 'niga'pidor'
> ^C
root@mars:~# echo 'niga\'pidor'
> ^C

3.1.2.3 Двойные Кавычки

Заключенные в двойные кавычки символы (' " ') отображаются буквально за исключением $, ~ и \ и если разворачивание из истории включено, то еще !. Когда шелл в режиме POSIX, то '!' не имеет специального значения в двойных кавычках, даже когда разворачивание из истории включено. '$' и '~' сохраняют свой особый смысл в двойных кавычках. Бэкслэш сохраняет специальное значение только когда за ним следует один из следующих символов: $, ~, ", \ или newline. В двойных кавычках бэкслэши, после которых идут перечисленные символы, будут удалены. Бэкслэши предшествующие символам без специального значения будут оставаться неизменными. Двойная кавычка может быть закавычена в двойные кавычки, с использованием предваряющего ее бэкслэша. Если разворачивание из истории включено, то оно будет выполняться пока '!' встречающийся в двойных кавычках не будет заэкранирован бэкслэшем. Предшествующий восклицательному знаку бэкслэш не удаляется.

Специальные параметры * и @ имеют специальное значение в двойных кавычках.


3.1.2.4 ANSI-C Кавычинг

Слова в форме $'string' обрабатываются по особому. Строка развернется в string, и заменит заэкранированные символы так как описано в ANSI C стандарте. Бэкслэшем заэкранированные последовательности, если они есть, будут декодированы следующим образом:

Результат разворачивания будет одинарно-закавыченный, как если бы знака доллара не было.

root@mars:~# echo $'aa\bb'
ab
root@mars:~# echo $'aa\fb'
aa
  b
root@mars:~# echo $'aa\nb'
aa
b
root@mars:~# echo $'aa\rb'
ba
root@mars:~# echo $'aa\tb'
aa	b
root@mars:~# echo $'aa\vb'
aa
  b
root@mars:~# echo $'aa\044b'
aa$b
root@mars:~# echo $'aa\x24b'
aa$b
root@mars:~# echo $'aa\u0024b'
aa$b
root@mars:~# echo $'aa\U00000024b'
aa$b

3.1.2.5 Локаль-специфичные Переводы

Строка в двойных кавычках с предшествующим долларом ('$') будет переведена основываясь на текущей локали. gettext выполнит поиск message catalog'a и перевод, используя переменные LC_MESSAGES и TEXTDOMAIN как объясняется ниже. Смотри документацию к gettext для дополнительных деталей. Если текущая локаль C или POSIX или если нет доступных переводов, то знак доллара будет проигнорирован. Если строка переведена и в ней выполнена замена, то результат будет в двойных кавычках.

Некоторые системы используют message catalog выбранный с помощью переменной LC_MESSAGES. Другие создают имя message catalog'a из значения переменной TEXTDOMAIN, возможно добавляя суффикс '.mo'. Если ты используешь переменную TEXTDOMAIN, тебе может потребоваться установить в переменную TEXTDOMAINDIR расположение файла message catalog'a. Некоторые все еще используют обе переменные таким образом: TEXTDOMAINDIR/LC_MESSAGES/LC_MESSAGES/TEXTDOMAIN.mo.


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

В неинтерактивном шелле или интерактивном, но с включенной shopt опцией interactive_comments, слова начинающиеся с '#' и вся дальнейшая строка за этим словом будет игнорироваться. В интерактивном шелле без опции interactive_comments комментарии не разрешены. Опция interactive_comments по умолчанию включена.

root@mars:~# shopt interactive_comments 
interactive_comments	off

root@mars:~# echo niga # pidor
niga # pidor

root@mars:~# shopt -s interactive_comments 

root@mars:~# shopt interactive_comments 
interactive_comments	on

root@mars:~# echo niga # pidor
niga

3.2 Команды Шелла

Такие простые команды как echo a b c состоят из самой команды и следующих за ней аргументов разделенных пробелами.

Множество комплексных шелл команд состоят из простых команд объединенных вместе различными способами: пайплайном в котором вывод одной команды входит в ввод следующей, циклом или условной конструкцией, или каким-то другим способом.


3.2.1 Зарезервированные Слова

Зарезервированные слова это слова которые имеют специальное значение для шелла. Они используются для начала и окончания составных команд.

Следующие слова известны как зарезервированные когда они незаковычены и являются первым словом в команде:

if then elif else fi time
for in until while do done
case esac coproc select function
{ } [[ ]] !

in распознается как зарезервированное слово если оно третье после команды case или select. in и do распознаются как зарезервированные слова если они третьи после команды for.


3.2.2 Простые Команды

Простые команды это вид команд который встречается чаще всего. Это просто последовательность слов разделенная с помощью blanks и заканчивающаяся одним из контрольных операторов шелла. Первое слово обычно определяет выполняемую команду, оставшиеся слова будут аргументами команды.

Статускод простой команды это exit status предоставляемый функцией waitpid стандарта POSIX 1003.1, или 128+n если команда была завершена сигналом n.


3.2.3 Пайплайны

Пайплайн это последовательность из одной или более команд разделенных операторами управления '|' или '|&'.

Формат пайплайнов

[time [-p]] [!] command1 [ | or |& command2 ] …

Вывод каждой команды в пайплайне соединяется через пайп с вводом следующей команды. То есть каждая команда читает аутпут предыдущей команды. Это соединение устанавливается до каких-либо перенаправлений определенных командой.

Если используется |&, то stderr вместе с stdout command1, подключается к stdin command2 через пайп; это сокращение для 2>&1 |. Это подразумевает что перенаправление stderr в stdout будет выполнено после редиректов определенных командой.

Я не понял два абзаца выше, поэтому вот оригинал:

The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command’s output. This connection is performed before any redirections specified by the command.

If ‘|&’ is used, command1’s standard error, in addition to its standard output, is connected to command2’s standard input through the pipe; it is shorthand for 2>&1 |. This implicit redirection of the standard error to the standard output is performed after any redirections specified by the command.

Зарезервированное слово time выводит статистику времени выполнения пайплайна. Статистика содержит затраченное время и время в user и system спейсах. Опция -p изменяет формат вывода на определенный POSIX'ом. Когда шелл в POSIX режиме ...