Jump to content

Bash (Українська)/Prompt customization (Українська)

From ArchWiki

У Bash існує кілька запрошень командного рядка, кожне з яких можна налаштувати на основі особистих уявлень про зручність та естетичність.

Запрошення

Bash має чотири рядки запрошення, кожен з яких може бути налаштований.

  • PS1 - головне запрошення, яке з'являється перед кожною командою; з цієї причини вона змінюється найчастіше.
  • PS2 - Друге запрошення відображається, якщо команда вимагає введення додаткових даних (наприклад, у випадку багаторядкових команд).
  • PS3 використовується рідко. З'являється, коли виконується вбудована команда Bash select, і відображається інтерактивне меню. На відміну від інших запрошень, не розкриває. Зазвичай всі зміни застосовуються безпосередньо до скрипту, що містить select, а не до файлу . bashrc.
  • PS4 - також рідко використовується. При налагодженні скриптів відображаються рівні вкладеності - перший символ запрошення повторюється стільки разів, скільки в даний час є активних рівнів.

Встановлення конкретного запрошення передбачає призначення (зазвичай у файлі ~/.bashrc) потрібного рядка змінній, наприклад:

PS2='> '

Техніки

Завжди можна зробити запрошення явним, але є ряд прийомів, які роблять його більш динамічним і корисним.

Escape-послідовності Bash

Коли рядок запрошення виводиться, Bash шукає символи втечі (послідовності втечі) і перетворює їх у спеціальні рядки. Наприклад, \u перетвориться в ім'я користувача, а \A - в поточний час.Таким чином, якщо змінній PS1 призначити '\A \u $ ', то запрошення буде виглядати так : 17:35 користувач $

Весь список escape-послідовностей можна знайти в керівництві bash(1) § PROMPTING та довіднику Bash.

Escape-послідовності terminfo

Крім escape-послідовностей, які розуміє Bash, більшість терміналів також розпізнають спеціальні послідовності, які впливають на термінал сам собою, а не на друковані символи. Наприклад, можна змінити колір рядка символів, зрушити курсор у довільну позицію або очистити екран. Ці послідовності можуть бути досить незручними та варіюються від терміналу до терміналу, тому вони задокументовані у базі даних terminfo. Щоб побачити, які властивості підтримує термінал, виконайте:

$ infocmp

Значення властивостей можна знайти в terminfo(5) за назвами (частина перед =). Наприклад, властивість setaf налаштовує колір шрифту для тексту, який буде надрукований після нього. Дізнатися про escape-код властивості можна командою tput. Наприклад,

$ tput setaf 2

виведе escape-послідовність для налаштування зеленого кольору шрифту.

Примітка: Якщо tput не працює, переконайтеся, що значення TERM має правильне значення для терміналу. Наприклад, якщо встановлено значення xterm замість xterm-256color, то tput setaf працюватиме лише з номерами кольорів 0-7.

На практиці, щоб використовувати ці можливості у запрошенні командного рядка, можна використовувати підстановку команд Bash та інтерполяцію рядків. Наприклад:

GREEN="\[$(tput setaf 2)\]"
RESET="\[$(tput sgr0)\]"

PS1="${GREEN}my prompt${RESET}> "
my prompt>
Примітка: Посібник Bash рекомендує "обернути" висновок tput \[ \]. Це допоможе Bash правильно враховувати недруковані символи під час обчислення довжини запрошення. Під час встановлення команд це не працює, тому використовуйте значення \1 \2.

Escape-послідовності ANSI

На жаль, ANSI-послідовності можуть бути відсутні в базі terminfo вашого терміналу. Найчастіше це стосується послідовностей для нових можливостей на кшталт підтримки 256 кольорів. У цьому випадку використовувати tput не вийде і доведеться вводити escape-послідовність вручну.

Приклади escape-послідовностей можна знайти у статті Керувальні послідовності ANSI.Кожна послідовність починається з літералу escape-послідовності, яку можна ввести за допомогою escape-послідовності Bash \e. Наприклад, \e[48;5;209m задасть персиковий колір фону (якщо є підтримка 256 кольорів), а \e[2;2H зрушить курсор у лівий верхній кут екрана.

Якщо escape-послідовності Bash не підтримуються (як у запрошенні PS3), їх можна додати командою printf:

ESC = $ (printf "e")
PEACH="$ESC[48;5;209m"

Вбудовані команди

Якщо ви хочете додати висновок якоїсь команди на запрошення, то використовуйте підстановку команд (command substitution). Наприклад, щоб додати величину вільної пам'яті до запрошення, спробуйте щось на зразок:

PS1="$(awk '/MemFree/{print $2}' /proc/meminfo) prompt > "
53718 prompt >
53718 prompt >
53718 prompt >

Як бачимо, це працює не зовсім коректно - значення пам'яті завжди одне й те саме! Причина — команда виконується лише один раз при першому налаштуванні PS1. Необхідно запобігти підстановці або екрануванням символу $, або визначенням рядка в одиночних лапках — в обох випадках підстановка буде проводитися щоразу при відображенні запрошення:

PS1="\$(awk '/MemFree/{print \$2}' /proc/meminfo) prompt > "
# или
PS1='$(awk "/MemFree/{print \$2}" /proc/meminfo) prompt > '

Якщо команди зробили запрошення надто довгим, для кращої читабельності можна винести їх у функцію:

free_mem()
{
    awk '/MemFree/{print $2}' /proc/meminfo
}

PS1='$(free_mem) prompt > '
Примітка: У підстановочних функціях можна використовувати escape-послідовність terminfo/ANSI, але не послідовності Bash. Зокрема, \[ \] не буде працювати при обрамленні ними рядка з символами, що не друкуються. Натомість використовуйте восьмеричні екрановані послідовності \001 і \002 (наприклад, у командах printf або echo -e).

PROMPT_COMMAND

Змінною PROMPT_COMMAND можна надати довільну команду, яка буде виконуватися безпосередньо перед виведенням PS1. Це дозволяє створювати досить сильні ефекти. Наприклад, можна перепризначити PS1 на основі деяких умов або виконати якісь дії з історією Bash під час виконання будь-якої команди.

Попередження: PROMPT_COMMAND не повинна використовуватися для виведення символів безпосередньо на запрошення. Символи, надруковані поза PS1, не враховуються Bash, що може призвести до неправильного позиціонування курсору та звичайних символів. Або використовуйте PROMPT_COMMAND для завдання PS1, або вивчіть рекомендації у розділі #Вбудовані команди.
Порада: Якщо PROMPT_COMMAND стала надто складною, bash-preexec (реалізація хук-функцій preexec і precmd ssh].

Escape-послідовності між введенням та виведенням

Властивості тексту можна змінити, "забувши" відключити властивості в кінці PS1. Наприклад, якщо вставити tput blink в кінець PS1, то команди, що вводяться, мерехтіть. Проте цей ефект також перейде і на виведення команди, оскільки властивості не відключаються при натисканні Enter.

Щоб вставити escape-послідовність після введення, але перед початком виведення можна перехопити (trap) Bash-сигнал DEBUG, який посилається перед виконанням кожної команди:

$ trap 'tput sgr0' DEBUG

Налаштування запрошення root

Для зручності можна зробити запрошення командного рядка root-користувача візуально відмінним від звичайного (можливо мерехтливий червоний колір?). Налаштування запрошення здійснюється як завжди, але в домашньому каталозі суперкористувача /root. Почніть з копіювання шаблонів /etc/skel/.bash_profile та /etc/skel/.bashrc до каталогу /root, після чого внесіть у файл /root/.bashrc необхідні зміни.

Приклади

Кольори

Порада: Висновок infocmp містить доступну для tput кількість кольорів, наприклад - colors#8.

Побачити всі кольори вашого терміналу можна за допомогою простого циклу (замініть setab на setaf, якщо потрібен колір тексту, а не тла):

for C in {0..255}; do
    tput setab $C
    echo -n "$C "
done
tput sgr0
echo

Якщо це не працює (причому встановлено правильне значення TERM), протестуйте вручну різні послідовності:

# стандартні кольори
for C in {40..47}; do
    echo -en "\e[${C}m$C "
done
# кольори високої інтенсивності
for C in {100..107}; do
    echo -en "\e[${C}m$C "
done
# 256 кольорів
for C in {16..255}; do
    echo -en "\e[48;5;${C}m$C "
done
echo -e "\e(B\e[m"

Аналогічні значення для тексту (не фону): стандартні - 30..37, висока інтенсивність - 90..97, а для 256 кольорів замініть 48 на 38.

Основні властивості

Наступні властивості terminfo будуть корисні при налаштуванні запрошення та підтримуються у багатьох терміналах. #1 і #2 необхідно замінити на числові аргументи.

Властивість Escape-послідовність Опис
Властивості тексту
blink \E[5m мерехтливий тект вкл
bold \E[1m напівжирний текст вкл
dim \E[2m тьмяний текст вкл
rev \E[7m зворотне відображення вкл (текст/фон змінюються кольорами)
sitm \E[3m курсив вкл
ritm \E[23m курсив викл
smso \E[7m виділення тексту вкл
rmso \E[27m виділення тексту викл
smul \E[4m підкреслення вкл
rmul \E[24m підкреслення викл
setab #1 \E[4#1m встановити колір фону #1 (0-7)
setaf #1 \E[3#1m задати колір тексту #1 (0-7)
sgr0 \E(B\E[m відключити всі атрибути тексту
Переміщення курсору
sc \E7 зберегти позицію курсору
rc \E8 повернути курсор у збережену позицію
clear \E[H\E[2J очистити екран і перемістити курсор у лівий верхній кут
cuu #1 \E[#1A перемістити курсор вгору на #1 рядків
cud #1 \E[#1B перемістити курсор вниз #1 рядків
cuf #1 \E[#1C перемістити курсор вправо #1 стовпців
cub #1 \E[#1D перемістити курсор вліво #1 стовпців
home \E[H перемістити курсор у лівий верхній кут вікна
hpa #1 \E[#1G перемістити курсор у стовпець #1
vpa #1 \E[#1d перемістити курсор у рядок #1, перший стовпець
cup #1 #2 \E[#1;#2H перемістити курсор у рядок #1, стовпець #2
Видалення символів
dch #1 \E#1P видалити #1 символів (аналогічно натисканню клавіші backspace)
dl #1 \E#1M видалити #1 рядків
ech #1 \E#1X стерти #1 символів (без переміщення курсору)
ed \E[J очистити до нижнього краю екрану
el \E[K очистити до кінця рядка
el1 \E[1K очистити до початку рядка

Відображення коду виходу

Тим же прийомом, як у вбудованих команд, можна відкласти інтерполяцію спеціальної змінної Bash на кшталт $?. Наступні запрошення матимуть код виходу попередньої команди:

PS1="\$? > "
# или
PS1='$? > '
0 > true
0 > false
1 >

Це можна зробити за допомогою умовних виразів та функцій:

exitstatus()
{
    if [[ $? == 0 ]]; then
        echo ':)'
    else
        echo 'D:'
    fi
}
PS1='$(exitstatus) > '
:) > true
:) > false
D: >

Позиціонування курсору

Курсор можна переміщати по екрану під час знаходження "всередині" запрошення PS1, щоб різні частини запрошення з'являлися у різних місцях. Важливий момент – після всіх переміщень та виведення символів у будь-яких місцях екрана курсор необхідно повернути у вихідну позицію. Це можна зробити за допомогою властивостей sc та rc, які зберігають та відновлюють позицію курсору відповідно. Загальна схема запрошення, що містить переміщення курсору:

PS1="\[$(tput sc; переміщення курсора) робота з курсором $(tput rc)\] робота з курсором після повернення"

Весь блок з переміщеннями курсору обернутий в \[ \], щоб Bash не враховував символи, що не друкуються, як частина запрошення.

Вирівнювання по правому краю

Найпростіший спосіб надрукувати текст у правого краю екрана – використовувати printf:

rightprompt()
{
 printf "%*s" $COLUMNS "right prompt"
}

PS1='\[$(tput sc; rightprompt; tput rc)\]left prompt > '
left prompt > right prompt

Тут встановлено поле %*s змінної довжини з вирівнюванням по правому краю. Розмір поля дорівнює поточній кількості стовпців у терміналі ($COLUMNS).

Довільне позиціонування

Властивість cup переміщує курсор у конкретну позицію екрану, наприклад tput cup 20 5 перемістить курсор на рядок 20, стовпець 5 (координати 0 0 позначають верхній лівий кут). cuu, cud, cuf і cub (вгору, вниз, вперед, назад) переміщують курсор щодо поточної позиції. Наприклад, tput cuf 10 перемістить курсор на 10 символів праворуч. В аргументах можна використовувати змінні LINES та COLUMNS, якщо потрібно перемістити курсор щодо нижнього та правого країв вікна. Наприклад, переміщення на 10 рядків та 5 стовпців від правого нижнього кута:

$ tput cup $((LINES - 11)) $((COLUMNS - 6))

Налаштування назви вікна терміналу

Назву вікна терміналу можна налаштувати так само, як і запрошення: виведенням escape-послідовностей в оболонці. Часто користувачі вбудовують налаштування назви вікна у своє запрошення. Технічно це можливість xterm, а й інші сучасні термінали її підтримують. У цьому випадку використовують послідовності ESC]2;нова назва'BEL, де ESC і 'BEL - символи escape (вихід) і bell (сигнал). З послідовностями Bash запрошення з вбудованою назвою вікна буде мати вигляд:

PS1='\[\e]2;нова назва\a\]prompt > '

Зрозуміло, що рядок назви вікна може включати висновок вбудованих команд або змінні на кшталт $PWD, так що вона може переналаштовуватися після кожної команди.

Дивіться також