Хабрахабр

Красные глаза

Привет, представляю вашему вниманию небольшой туториал по оформлению приглашения командной строки с эффектом красных глаз.
Все кто работал в консоли какого-нибудь Линукса наверно отмечали удобную особенность отображать текущую папку, имя пользователя, имя сервера и что-то еще в зависимости от дистра в строке приглашения. Мне тоже это всегда нравилось. Но иногда получалось вот так:

Сложно «творить» в строке из трех символов, конечно курсор переходит на следующую строку но это скорей еще больше бесит чем помогает. И вот в какой-то момент я сказал себе:

Я решил вернуть себе все пространство командной строки и больше не отдавать никому и никогда. Встал вопрос, как изменить текст приглашения командной строки? Оказалось, очень просто, достаточно изменить специальную системную переменную `PS1`.

Да, прямо в терминале можно задать новый текст приглашения. Но как сохранить изменения? Да и без информации о текущем каталоге как-то неуютно себя чувствуешь, постоянно задаешь себе вопрос: «Где я?» Поможет файл ~/.bashrc, в нём можно сохранить изменение PS1, а чтобы информация о текущей директории не занимала рабочее пространство, я решил разместить её не В а НАД командной строкой. Добавим в файл ~/.bashrc строку:

PS1='$PWD\n# '

Обратите внимания на одинарные кавычки, если мы используем двойные, то вместо указателя на переменную $PWD (системная переменная, в которой хранится полный путь текущей папки, аналог команда pwd) в строку приглашения запишется ее значение(текущий каталог) и меняться при переходе из папки в папку не будет. Выглядит это так:

Командная строка полностью свободна, но имя папки сливается с содержимым если выполнить команду ls. Придется отделить мух от котлет имя папки от содержимого. Я решил добавить «рамки» для $PWD, добавив сверху и снизу строки из символов "-". Как узнать количество символов в строке? Для этого тоже есть системная переменная $COLUMNS. А чтобы быстро сформировать строку с необходимым количеством символов "-" воспользуемся командой printf:

printf -v line "%${COLUMNS}s"

Эта команда создаст переменную $line и заполнит её пробелами в количестве $COLUMNS но нам нужны не пробелы а "-", для этого используем следующий трюк:

line=${line// /-} # заменить все пробелы на -

Добавим этот код в ~/.bashrc

printf -v line "%${COLUMNS}s"line=${line// /-}PS1='\n$line\n$PWD\n$line\n# '

Отлично, но если сейчас изменить размер окна терминала, размер «линий» не изменится и красота пропадет:

Чтобы поправить ситуацию перенесем новый код в функцию info и добавим её в PS1:

info () { printf -v line "%${COLUMNS}s" line=${line// /-} printf "\n$line\n$PWD\n$line\n# "}PS1='$(info)'

Можно совместить приятное с полезным, добавив в верхний ограничитель «вставку» с именем хоста. Вставка с именем будет посередине, для этого нам необходимо вычислить центр линии(с учетом длинны названия хоста и доп. символов):

info () { name_length="{ $HOSTNAME }" name_length=${#name_length} top_line_left=$[(COLUMNS-name_length)/2] top_line_right=$[COLUMNS-(top_line_left+name_length)] printf -v top_line "%${top_line_left}s{_S_${HOSTNAME}_S_}%${top_line_right}s" printf -v bot_line "%${COLUMNS}s" bot_line=${bot_line// /-} top_line=${top_line// /-} top_line=${top_line//_S_/ } printf "\n$top_line\n$PWD\n$bot_line\n# "}PS1='$(info)'

Я заключил имя хоста в фигурные скобки с пробелами, но вместо пробелов вокруг $HOSTNAME используются символы "_S_" которые затем меняются на пробелы. Это необходимо потому, что в итоговой строке все пробелы заменяются на "-", а внутри вставки должны остаться пробелы. Добавим красок, для этого подготовим переменные с кодами изменения цвета текста в терминале, я использовал такие цвета:

RED='\e[31m' # красныйGRN='\e[32m' # зелёныйYLW='\e[33m' # жёлтыйBLU='\e[34m' # синийMGN='\e[35m' # пурпурныйDEF='\e[0m' # вернуть значения по умолчаниюBLD='\e[1m' # жирноDIM='\e[2m' # тускло

Добавим эти переменные в наш код:

info () { name_length="{ $HOSTNAME }" name_length=${#name_length} top_line_left=$[(COLUMNS-name_length)/2] top_line_right=$[COLUMNS-(top_line_left+name_length)] printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME${DEF}_S_$GRN}%${top_line_right}s" printf -v bot_line "%${COLUMNS}s" bot_line=$GRN${bot_line// /-}$DEF top_line=${top_line// /-} top_line=$GRN${top_line//_S_/ }$DEF printf "\n$top_line\n$BLD$BLU$PWD$DEF\n$bot_line\n# "}PS1='$(info)'

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

printf -v date "%(%a %d %b %T)T"

Чтобы разместить это справа необходимо добавить какое-то количество пробелов после $PWD, какое, давайте посчитаем:

center_space=$[COLUMNS-${#date}-${#PWD}]((center_space<0)) && center_space=1...printf "\n$top_line\n$BLD$BLU$PWD$DEF%${center_space}s$DIM$date\n$bot_line\n# "

Можно ли сделать лучше? Конечно, добавим вывод git status если находимся в папке с git проектом:

 git_tst= git_clr= [[ -d .git ]] && { git_tst=(GIT $(git status -sb)) git_tst="${git_tst[*]} " # простой для теста git_clr=(GIT $(git -c color.ui=always status -sb)) git_clr="${git_clr[*]} " # цветной для вывода } ... center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}] ... printf "\n$top_line\n$BLD$BLU$PWD$DEF%${center_space}s${git_clr[*]}$DIM$date\n$bot_line\n\$ "

Обратите внимания что git_clr и git_tst сначала записываются массивом, а затем преобразуются в переменные. Это необходимо для того чтобы удалить переходы строки из вывода git status. Но где же глаза? Сейчас будут глаза О_о, создадим массив с базовым набором глаз:

eyes=(O o ∘ ◦ ⍤ ⍥)

И посчитаем их количество:

en=${#eyes[@]}

Добавим символ рта:

mouth='_'

И сделаем генератор случайных морд:

face () { printf "$YLW${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}$DEF"}

Глаза будут находиться по краям информационного поля, необходимо учесть их при расчете количества пробелов в середине, подготовим для этого отдельную переменную:

face_tst='O_o o_O'...center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}-${#face_tst}]printf "\n$top_line\n$(face) $BLD$BLU$PWD$DEF%${center_space}s$git_clr$DIM$date $(face)\n$bot_line\n\$ "

Как заставить глаза покраснеть? Долго сидеть за компом, не спать На stackoverflow.com мне попался интересный вопрос, автор спрашивает: «как менять цвет в приглашении командной строки на красный если последняя команда завершилась неудачно?» Это и натолкнуло меня на идею красных глаз. Добавим в функцию info запоминание статуса завершения последней команды:

info () { error=$? ...}

И изменим функцию face таким образом, чтобы она проверяла переменную $error и в зависимости от её значения красила глаза в красный или жёлтый:

face () { [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"}

Ну вот у меня глаза покраснели, но можно добавить еще кое-что. Добавим проверку переменной $debian_chroot:

[[ $debian_chroot ]] && chrt="($debian_chroot)" || chrt=...name_length="{ $HOSTNAME$chrt }"...printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME$chrt${DEF}_S_$GRN}%${top_line_right}s"

И изменим текст в заголовке окна терминала:

PS1='$(info)'; case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;$(face 1) \w\a\]$PS1";; esac

В заголовок будет выводится морда и текущий каталог, но придется немного доработать функцию face чтобы она рисовала морду без цветовых кодов, они в заголовке бутут отображаться просто текстом, передадим функции face какой-нибудь параметр (например «1»), внутри функции добавим проверку, если задан 1-й аргумент, выдать морду без разукрашивания:

face () { [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW [[ $1 ]] && printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}" \ || printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"}

Итоговый скрипт:

RED='\e[31m' # красныйGRN='\e[32m' # зелёныйYLW='\e[33m' # жёлтыйBLU='\e[34m' # синийMGN='\e[35m' # пурпурныйDEF='\e[0m' # вернуть значения по умолчаниюBLD='\e[1m' # жирноDIM='\e[2m' # тусклоeyes=(O o ∘ ◦ ⍤ ⍥) en=${#eyes[@]} mouth='_'face () { [[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW [[ $1 ]] && printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}" \ || printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"}info () { error=$? git_tst= git_clr= [[ -d .git ]] && { git_tst=(GIT $(git status -sb)) git_tst="${git_tst[*]} " # простой для теста git_clr=(GIT $(git -c color.ui=always status -sb)) git_clr="${git_clr[*]} " # цветной для вывода } [[ $debian_chroot ]] && chrt="($debian_chroot)" || chrt= name_length="{ $HOSTNAME$chrt }" name_length=${#name_length} face_tst='O_o o_O' top_line_left=$[(COLUMNS-name_length)/2] top_line_right=$[COLUMNS-(top_line_left+name_length)] printf -v top_line "%${top_line_left}s{_S_$DEF$BLD$HOSTNAME$chrt${DEF}_S_$GRN}%${top_line_right}s" printf -v bot_line "%${COLUMNS}s" printf -v date "%(%a %d %b %T)T" top_line=${top_line// /-} top_line=$GRN${top_line//_S_/ }$DEF bot_line=$GRN${bot_line// /-}$DEF center_space=$[COLUMNS-${#date}-${#PWD}-${#git_tst}-${#face_tst}] ((center_space<0)) && center_space=1 printf "\n$top_line\n$(face) $BLD$BLU$PWD$DEF%${center_space}s$git_clr$DIM$date $(face)\n$bot_line\n\$ "}PS1='$(info)'; case "$TERM" in xterm*|rxvt*) PS1="\[\e]0;$(face 1) \w\a\]$PS1";; esac

На этом все, спасибо за внимание!) Подписывайтесь, ставьте лайки, вот это вот все, проект есть в гитхабе info-bar Творите, выдумывайте, пробуйте!)

проверка внимательности

Вы заметили в какой момент символ "#" в строке приглашения поменялся на "$"?)

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть