Практическое написание сценариев командной оболочки Bash/Приложения

Материал из Викиучебника — открытых книг для открытого мира
Перейти к навигации Перейти к поиску
← Код-сниппеты Глава
Приложения


Получение цветовой схемы терминала[править]

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

\e[##m

где вместо ## нужно подставить определенные коды, отвечающие за отображение.

Символы \e и [ начинают любую управляющую последовательность, а сама пара называется CSI (от Control Sequence Introducer). Вместо \e допустимо записывать \033, т.е.

\033[##m

однако так запись кажется не такой опрятной.

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

   \e[0m        # Сброс отображения к значению по умолчанию
   \e[1m        # Полужирное начертание
   \e[2m        # Приглушенный цвет
   \e[4m        # Яркий цвет
   \e[5m        # Мигание
   \e[7m        # Инвертирует фон литеры с ее цветом, например белый цвет на черном фоне инвертируется в черный цвет на белом фоне
   \e[22m       # Установить нормальную интенсивность
   \e[24m       # Убрать подчеркивание
   \e[25m       # Убрать мигание
   \e[27m       # Отменить реверсивное начертание
   \e[30m       # Черный цвет для символа
   \e[31m       # Красный цвет для символа
   \e[32m       # Зеленый цвет для символа
   \e[33m       # Желтый цвет для символа
   \e[34m       # Синий цвет для символа
   \e[35m       # Фиолетовый цвет для символа
   \e[36m       # Голубой цвет для символа
   \e[37m       # Серый цвет для символа
   \e[39m       # Сбросить цвет символа к значению по умолчанию
   \e[40m       # Черный фон для символа
   \e[41m       # Красный фон для символа
   \e[42m       # Зеленый фон для символа
   \e[43m       # Желтый фон для символа
   \e[44m       # Синий фон для символа
   \e[45m       # Фиолетовый фон для символа
   \e[46m       # Голубой фон для символа
   \e[47m       # Серый фон для символа
   \e[49m       # Сбросить фон символа к значению по умолчанию

С полным списком управляющих последовательностей ANSI вы можете познакомиться на следующей странице.

Вы можете в любой момент поэкспериментировать с управляющими последовательностями, например так

echo -e "\e[7mTest text\e[0m Text after"
# Выведет Test text с инверсией цветов (черный на белом)

# За один раз можно использовать несколько последовательностей
echo -e "\e[7m\e[36mTest text\e[0m Text after"
# Выведет Test text с инверсией цветов (черный на голубом)

Вы можете обойтись одним CSI, если будете перечислять коды через точку с запятой. Коды будут применяться именно в том порядке, в котором следуют.

echo -e "\e[33;42;1mTest text\e[0m Text after"
# Выведет полужирный (1) желтый цвет (33) на зеленом фоне (42).

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

echo
for x in 0 1 4 5 7 8; do
    for i in $(seq 30 37); do
        for a in $(seq 40 47); do
            echo -ne "\e[$x;$i;$a""m\\\e[$x;$i;$a""m\e[0;37;40m "
        done; echo
    done
done
echo
Пример интерпретации управляющих последовательностей в эмуляторе терминала xterm

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

   \e[0;48;5;NNNm    # для инвертированного цвета
   \e[0;38;5;NNNm    # для нормального цвета

# где вместо NNN нужно использовать код от 0 до 255. Например, \e[0;48;5;16m это инверсия (белый на черном).

# Сброс осуществляется все тем же \e[0m.

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

echo  
for i in $(seq 0 255); do
    printf "\e[0;48;5;${i}m %03d\e[0;38;5;${i}m %03d " $i $i
    [[ $i -eq 7 || $i -eq 15 || $i -eq 231 || $i -eq 239 || $i -eq 247 ]] && echo
    [[ $i -ge 15 && $i -le 231 && $(( ($i - 15) % 6 )) -eq 0 ]] && echo
done
echo
Пример интерпретации управляющих последовательностей в эмуляторе терминала xterm

Горячие клавиши командной оболочки[править]

Замечания
  • Перечисляемые здесь горячие клавиши могут не работать в вашей системе по той причине, что они не настроены или настроены по-другому. Обычно сочетания горячих клавиш хранятся в файле .inputrc домашней директории пользователя. Если этого файла нет, то просматривается файл /etc/inputrc. Для ознакомления со структурой этого файла обратитесь к официальной документации. Чтобы посмотреть какие клавиши сейчас настроены, используйте команду bind -P.
  • В официальной документации можно встретить такую нотацию по горячим клавишам, которая не понятна, если читатель столкнулся с документацией в *nix впервые:
    • Любое сочетание, описываемое как С-x (где x любая клавиша на клавиатуре), означает Ctrl + x. На некоторых страницах в том же значении оно может быть выражено как ^x.
    • Любое сочетание, описываемое как M-x (где x любая клавиша на клавиатуре), означает Alt + x. M означает в этом контексте Meta. Это обусловлено историческими причинами: старые клавиатуры действительно имели клавишу Meta, которая имела наклейку в виде ромбика. В современных клавиатурах эта клавиша отсутствует и может эмулироваться клавишой Alt / ⊞ Win / ⌥ Option в зависимости от настроек клавиатуры.
  • На старых клавиатурах не было клавиш со стрелками, поэтому вас может удивить то, что в документации движение курсора настроено на буквы, а про стрелки вообще не сказано ни слова. В современных дистрибутивах движение курсора по стрелкам работает.
  • По умолчанию Bash использует сочетания клавиш, пришедшие из редактора Emacs. Существует опция, позволяющая переключить комбинацию на схему, используемую в vi, но так как практически большинство современных разработчиков знает именно сочетания Emacs, вряд ли вы захотите это сделать.

Перемещение каретки в интерактивном режиме[править]

Позиция каретки на строке

Сочетание Что происходит Позиция курсора до Позиция курсора после

Ctrl+ или
 Alt+f

Движение курсора вперед на одно слово (если в строке есть слеш, то разделителем слов будет считаться слеш) $ less /etc/hosts $ less /etc/hosts

Ctrl+ или
 Alt+b

Движение курсора назад на одно слово (если в строке есть слеш, то курсор переместиться на первую позицию после него) $ less /etc/hosts  $ less /etc/hosts

Ctrl+e

Переместить курсор в конец строки $ less /etc/hosts $ less /etc/hosts 

Ctrl+a

Переместить курсор в начало строки $ less /etc/hosts  $ less /etc/hosts

Ctrl+f

Переместить курсор на один символ вперед $ less /etc/hosts $ less /etc/hosts

Ctrl+b

Переместить курсор на один символ назад $ less /etc/hosts $ less /etc/hosts

Работа с символами под курсором[править]

Сочетание Что происходит Позиция курсора до Позиция курсора после

Ctrl+d

Удаляет символ под курсором $ less /etc/hosts $ ess/etc/hosts

Ctrl+k

Удалить все символы начиная с текущего и до конца строки $ less /etc/hosts $ less 

Ctrl+t

Поменять текущий символ с впередистоящим местами $ elss /etc/hosts $ less /etc/hosts

Ctrl+u

Удалить все символы, начиная с предстоящего от текущего и до начала строки $ less /etc/hosts $  /etc/hosts

Ctrl+w или
 Alt+← Backspace

Удалить впередистоящее слово (слеши при этом разделителями слов не считаются) $ less /etc/hosts  $ less  

Alt+l

Перевести символы всего следующего слова от курсора в нижний регистр $ LESS /etc/hosts $ less /etc/hosts

Alt+u

Перевести символы всего следующего слова от курсора в верхний регистр $ echo HELLO world $ echo HELLO WORLD 

Alt+c

Переводит первый символ слова в верхний регистр, а все остальные в нижний $ echo HELLO world $ echo Hello world

Ctrl+l

Очистить экран подобно команде clear
Примечание
Сочетание Ctrl+w интерпретируется терминальным устройством, а не оболочкой, но сюда оно вставлено, потому что так логично для изложения.

Работа с текущей строкой[править]

Знакомое вам сочетание «копировать-вставить» в Bash не работает (если эмулятор терминала его не поддерживает), потому что в те далекие времена концепции буфера обмена еще не было (по крайней мере, в той форме, в которой это понимается сейчас).

Обычная последовательность операций в Bash это автодополнение, вырезание фрагмента и/или вставка вырезанного фрагмента. Для ввода большого фрагмента, где любая ошибка чревата повторным вводом, можно воспользоваться редактором, который по завершении выдаст результат в оболочку.

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

  • Ctrl+w — вырезать впереди стоящее от курсора слово;
  • Ctrl+u — вырезать весь впереди стоящий фрагмент строки относительно курсора;
  • Ctrl+k — вырезать весь фрагмент от курсора и до конца строки.

Вырезанное можно затем вставить комбинацией Ctrl+y. Вы можете вставить вырезанный фрагмент сколько угодно раз.

В Bash реализован круговой буфер: если вы много вырезали, то все варианты до поры до времени будут хранится в буфере. Вы можете перебирать вырезанные варианты из буфера комбинацией Alt+y.

Если вы ошиблись в своем предыдущем действии, то его можно отменить комбинацией Ctrl+⇧ Shift+_, либо вы можете вырезать фрагмент и повторить ввод.

Для длинных команд вы можете воспользоваться редактором. В старых версиях Bash редатор указывался в переменной окружения EDITOR (обычно эта переменная не определена, но вы можете определить ее в любое время задав конкретный редактор в форме пути или команды. Эта переменная проверяется в первую очередь). В современных версиях Bash используется редактор по символической ссылке, возвращаемой командой which editor.

Чтобы вызвать редактор, воспользуйтесь двойным сочетанием Ctrl+x, Ctrl+e. Bash переключится в некоторый редактор (например, vi), где вы можете ввести команду, пользуясь всеми удобствами редактора. Затем вам нужно выйти сохранив файл под именем, предложенным Bash. После этого Bash выполнит все команды из этого файла. Помните, что каждая строка файла интерпретируется как отдельный ввод.

Есть еще одно интересное сочетание, позволяющее закомментировать текущую введенную строку: Alt+⇧ Shift+#. Строка будет закомментирована, после чего автоматически будет введен ↵ Enter. Данная команда сохранится в истории команд, поэтому вы сможете ей воспользоваться позже, найдя ее в истории. Эта процедура напоминает чем-то копирование, где хранилищем выступает история.

Управляющие комбинации терминального устройства[править]

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

Чтобы посмотреть настройку текущего терминального устройства, используйте следующую команду

$ stty -a
speed 38400 baud; rows 30; columns 120; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S;
susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

Ниже перечислены наиболее часто используемые сигналы, которые можно послать с клавиатуры.

Сигнал Сочетание Пояснение
SIGINT Ctrl+c Обычно этот сигнал прерывает исполнение текущей команды оболочки
SIGTSTP Ctrl+z Обычно приостанавливает (ставит на паузу) выполнение задачи, выполняемой на переднем плане. Останавливаемая задача уходит на задний план. Чтобы продолжить ее на переднем плане, нужно использовать команду fg; чтобы продолжить ее на заднем плане — bg

Прочие управляющие последовательности представлены в таблице ниже.

Сочетание Пояснение
Ctrl+d Посылает в стандартный поток ввода текущей команды командной оболочки символ EOF (End of File). Сама оболочка Bash интерпретирует этот символ как завершение текущего сеанса пользователя. Другие программы могут интерпретировать этот символ по-разному, но обычно этот символ сигнализирует, что поток ввода окончен и можно выйти. Так делает например команда cat
Ctrl+v Позволяет сказать терминалу, что следующий вводимый символ нужно интерпретировать дословно. Очень наглядно это выглядит по нажатию клавиши Tab ↹. В обычных условиях командная оболочка перехватывает эту клавишу у терминала и запускает механизм автодополнения команды, но можно перехватить нажатие клавиши раньше на уровне терминала, тогда символ по этой клавише будет интерпретирован дословно самим терминалом. Например, если вы введете Ctrl+v, Tab ↹, то терминал будет интерпретировать управляющую последовательность \t, т.е. на экране появится смещение от табуляции

История команд[править]

Все команды, которые вы вводили под своей учетной записью, сохраняются в файл истории ~/.bash_history. Местонахождение этого файла вы сможете определить через вывод значения переменной HISTFILE. Каждая строка в файле это отдельная запись. Таких записей не может быть больше значения переменной HISTSIZE, которая обычно определяется в ~/.bashrc. В историю попадают не все команды, другими словами Bash использует параметр HISTCONTROL для отсеивания. Обычно он установлен в значение ignoreboth, что означает не фиксировать в истории команды, которые уже есть в истории, и не фиксировать пустые строки.

Основные приемы работы с историей[править]

  • Чтобы вывести весь файл истории, используется команда history. Если указать число, то выведет последние несколько команд, в соответствии с числом.
  • Чтобы подставить последнюю команду из истории, используется строка из двух восклицательных знаков (!!). Часто используемый сценарий применения этой возможности, это когда вы пытаетесь выполнить действие, требующее привилегий суперпользователя, но забыли ввести команду sudo. Следующие пример демонстрирует это.
    $ vi /etc/resolv.conf
    bash: /etc/resolv.conf permission denied
    
    $ sudo !! # Результат: sudo vi /etc/resolv.conf
    
  • Если вы знаете номер команды истории относительно последней, то можно воспользоваться номером. Так !-1 выведет последнюю команду истории на текущий момент, !-2 — предпоследнюю и так далее.
  • Если после восклицательного знака ввести несколько первых символов команды, то оболочка попытается найти первую совпадающую команду, начиная с конца.
    $ vi /etc/resolv.conf
    $ vi /etc/ssh/sshd_config
    
    $ !vi   # Ближайшая похожая команда vi /etc/ssh/sshd_config
    
  • Историю команд можно листать по клавишам со стрелками и . Если настроено, это также могут быть PageUp и PageDown.
Примечание
Для того чтобы PageUp и PageDown начали работать, нужно привязать их к функциям в файле inputrc следующим образом:
"\e[5~": history-search-backward
"\e[6~": history-search-forward
  • Можно брать аргументы предыдущей команды с помощью следующих переменных:
    • !!:$ или !:$ — взять последний аргумент предыдущей команды.
    • !!:0 или !:0 — взять первое слово предыдущей команды (обратите внимание, не аргумент, а именно слово). Обычно первым словом и является предыдущая команда.
    • !!:1 или !:1 — взять второе слово предыдущей команды.
    • !!:2 или !:2 — взять третье слово предыдущей команды.
    • и так далее
  • Предыдущий прием можно комбинировать с поиском первой похожей команды, если вместо второго восклицательного знака написать эту команду
    $ less /etc/ssh/sshd_config /etc/resolv.conf
    
    $ less !less:1 # Возьмет первый аргумент предыдущей команды, т.е.
                   # /etc/ssh/sshd_config
    
  • Историю можно очистить командой history -c. Удалить конкретную строку из истории можно командой history -d <номер строки>.
Примечание
Последний аргумент предыдущей команды также может быть вставлен через комбинацию Alt+⇧ Shift+_. Номер аргумента с конца можно указать, если сначала ввести комбинацию Alt+⇧ Shift+- (без ⇧ Shift можно обойтись, если использовать малую цифровую клавиатуру), затем нужно ввести номер и нажать комбинацию Alt+⇧ Shift+_.

Повторное выполнение фрагмента из истории[править]

Для повторного выполнения фрагмента истории вы должны перейти на желаемую команду с помощью стрелок или любым другим путем, а затем последовательно нажимать Ctrl+o. С каждым нажатием будет выполняться команда из истории, после чего на ее место будет вставать следующая команда.

Поиск по истории[править]

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

Основным методом поиска по истории является комбинация Ctrl+r, после которого командная оболочка предложит вам начать печатать первые несколько символов команды, которую вы когда-то вводили. По мере того как вы уточняете команду, вам будет предлагаться все более конкретный результат.

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

Чтобы сочетание Ctrl+s начало работать, вам нужно опустить специальный флаг терминального устройства IXON, который разрешает ручное управление потоком данных на устройство (т.е. сочетания Ctrl+s для остановки и Ctrl+q для продолжения):

stty -ixon

Для того чтобы закрепить эту настройку, необходимо в файл ~/.bashrc добавить (или скорректировать) примерно такой фрагмент:

case $- in                                     # Запросить опции оболочки, которые сейчас включены
  *i*) stty -ixon <... другие опции ...>  ;;   # Опция i говорит, что оболочка работает в интерактивном режиме
  ...
esac
Примечание
Если после нажатия Ctrl+s у вас остановился терминал, то чтобы продолжить работу нажмите Ctrl+q. Некоторые эмуляторы терминалов перехватывают это сочетание, но игнорируют его из-за по умолчанию отключенного флага IXOFF.

Если вы нашли нужную вам команду, вы можете нажать ↵ Enter, чтобы исполнить ее, либо Ctrl+j, чтобы остановить поиск и просто ввести найденную команду в оболочку (например, чтобы немного ее отредактировать). Если вы передумали что-либо искать, то нажмите Ctrl+g для отмены поиска, при этом ранее введенные символы будут восстановлены.

Остановить поиск можно также с помощью клавиш со стрелками.

Результат последнего поиска будет запомнен, а найденная строка становится текущей в истории.

Автодополнение[править]

Bash умеет автодополнять команды в зависимости от контекста. Инструкции для функции автодополнения обычно передаются через ~/.bashrc. Минимально Bash умеет дополнять известные системные команды, пути к файлам и каталогам и дополнять имена объявленных переменных окружения.

Активизировать механизм автодополнения можно:

  • Нажав Tab ↹.
  • Нажав дважды Esc.
  • Нажав Ctrl+i.

Если вариантов автодополнения много, то по первому нажатию будет написана общая часть из подмножества совпадений. По второму нажатию будут предложены все найденные варианты.

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

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

Для простого автодополнения переменной окружения нужно просто начать строку с символа доллара ($). Также Bash разрешает тильда-подстановки, если строка начинается на тильду (~), например, чтобы быстро ввести домашний каталог пользователя.

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

Важно
Следует обратить внимание на одну особенность, которая подробно в документации не объясняется, и наталкиваясь на нее, новички не всегда понимают как следует нажимать клавиши.
Возьмем к примеру комбинацию, которая в документации записана как C-x~. По этой комбинации Bash выведет список всех пользователей системы. Здесь написаны три клавиши, но на самом деле здесь нужно нажать последовательно две комбинации: Ctrl+x, ⇧ Shift+~, так как на клавише с тильдой есть еще символ апострофа. Другими словами, в документации передается какой символ нужно ввести, и если для символа нужна клавиша ⇧ Shift, то это подразумевается.
Допустим вы посмотрели список пользователей и захотели ввести нужного вам пользователя в команду аргументом. Для этого вы должны ввести хотя бы несколько начальных символов, чтобы имя однозначно сопоставлялось, а затем, согласно документации, нажать M-~. Опять же клавиша ⇧ Shift здесь подразумевается, т.е. полная последовательность Alt+⇧ Shift+~.
Ниже мы будем везде подписывать ⇧ Shift для большей ясности, какие клавиши нажимаются.
Данные Сочетание, чтобы посмотреть все варианты Сочетание, чтобы дополнить ввод
Имя пользователя системы Ctrl+x, ⇧ Shift+~ Alt+⇧ Shift+~ или
Esc+⇧ Shift+~
FQDN из /etc/hosts Ctrl+x, ⇧ Shift+@ Alt+⇧ Shift+@ или
Esc+⇧ Shift+@
Все переменные окружения сеанса Ctrl+x, ⇧ Shift+$ Alt+⇧ Shift+$ или
Esc+⇧ Shift+$
Список всех команд, видимых командной оболочке, в том числе их псевдонимы Ctrl+x, ⇧ Shift+! Alt+⇧ Shift+! или
Esc+⇧ Shift+!
Список файлов в текущем каталоге Ctrl+x, ⇧ Shift+\ | /

(Для этой комбинации нужно вводить слеш повернутый направо, т.е. написана клавиша, а не символ. Без ⇧ Shift слеш может быть введен с малой цифровой клавиатуры или по клавише с вопросом / ? ;)
Alt+⇧ Shift+\ | / или
Esc+⇧ Shift+\ | /

(Для этой комбинации нужно вводить слеш повернутый направо, т.е. написана клавиша, а не символ. Без ⇧ Shift слеш может быть введен с малой цифровой клавиатуры или по клавише с вопросом / ? ;)

Находясь в некоторой директории, вы можете подставить в команду сразу все файлы в этой директории, либо, если прописана часть префикса некоторой директории, то указанной директории. Для этого нужно нажать Alt+⇧ Shift+* или Ctrl+x, ⇧ Shift+*. Вообще, последнее сочетание просит разрешить glob-шаблон, поэтому вы можете вводить маскирующие символы в строку перед нажатием сочетания.

Символ звездочки может быть введен без ⇧ Shift через малую цифровую клавиатуру.



← Код-сниппеты