Bash: відображає статус виходу у запиті:


11
GREEN="\e[1;32m"
RED="\e[1;31m"
NONE="\e[m"

get_exit_status(){
   es=$?
   if [ $es -eq 0 ]
   then
       echo -e "${GREEN}${es}${NONE}"
   else
       echo -e "${RED}${es}${NONE}"
   fi
}

get_path(){
    #dummy function
    echo "PATH"
}

PROMPT_COMMAND='exitStatus=$(get_exit_status)'

Далі подано мені правильний exitStatus, але змінні кольорів не розширені:

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

Однак, наведений нижче, надає мені кольори, але статус виходу не оновлюється:

PS1="${RED}\h $(get_path) ${exitStatus}${NONE} "

Який правильний спосіб це зробити? Як я можу це виправити, щоб і функція exitStatus, і кольори працювали?

Відповіді:


8

Жил визначив вашу головну проблему, але я хотів спробувати пояснити її по-іншому.

Bash інтерпретує спеціальні запити проскакувань лише перед розширенням будь-яких змінних у підказці. Це означає, що використання \eзмінної, розширеної з підказки, не працює, навіть якщо вона працює безпосередньо в PS1.

Наприклад, це працює, як очікувалося, і дає червоний текст:

PS1='\e[1;31m this is in red '

Але це не робить, він просто ставить буквальне \eв підказку:

RED='\e[1;31m'
PS1="$RED not in red "

Якщо ви хочете зберегти кольорові кольори у змінних, ви можете використовувати ANSI-C quoiting ( $'...'), щоб поставити буквальний символ втечі у змінну.

Щоб зробити це, ви можете змінити своє визначення GREEN, REDі NONE, таким чином , їх значення є фактичною послідовністю виходу.

GREEN=$'\033[1;32m'
RED=$'\033[1;31m'
NONE=$'\033[m'

Якщо ви це зробите, ваш перший PS1з цитатами повинен працювати:

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

Однак тоді у вас виникне друга проблема.

Спробуйте виконати це, потім натисніть Up Arrow, а потім Homeваш курсор не повернеться до початку рядка.

Щоб виправити це, змініть, PS1щоб включити \[і \]навколо послідовностей виділення кольорів, наприклад

PS1='\[${RED}\]\h $(get_path) $?\[${NONE}\] '

Тут не можна get_exit_statusправильно використовувати , оскільки його вихід містить як друкуючу (код виходу), так і недрукувальну символів (кольорові коди), і немає ніякого способу правильно позначити її у запиті. Розміщення \[...\]позначило б це недруком у повному обсязі, що невірно. Вам доведеться змінити функцію, щоб вона друкувала лише належний кольоровий код, а потім оточувала їх \[...\]у запиті.


\[є \1, і \[є \2. Кому відповідає RL_PROMPT_{START,END}_IGNOREте, що вимагає, щоб вона ігнорувала байти під час підрахунку довжини запиту на екрані. Див. Списки.gnu.org/archive/html/bug-bash/2015-08/msg00027.html .
Arthur2e5

@ Arthur2e5 Ви маєте на увазі \]це \2? А ви маєте на увазі, що для цього це потрібно ${exitStatus}? Моя думка полягала в тому, ${exitStatus}що не містить символів, що не друкуються, тому bash повинен вміти правильно визначати, скільки символів він переміщує підказку без значень \[та \]в \[${exitStatus}\].
Мікель

Проблема в тому, що вона містить деякі - кольори. (ANSI Escapes)
Arthur2e5

@ Arthur2e5 Ew, я цілком пропустив це. :) Чому б ти поставив кольори ... неважливо. :)
Mikel

1
"Bash ефективно викликає ехо на вашому PS1, а не відлуння -e" - ну це неправильно або просто пропущено суть. Bash розгортає зворотні коси сліди, як \eі \033\[/ \], \uі \h), з підказки, це просто робиться перед розширенням змінних. Так PS1='\e[1;31m red'працює, red='\e[1;31m'; PS1='$red red'ні.
ilkkachu

3

При запуску PS1='${RED}\h $(get_path) ${exitStatus}${NONE} ', то PS1змінна встановлюється ${RED}\h $(get_path) ${exitStatus}${NONE}, де тільки \hце запрошення послідовність виходу. Після того, як послідовності підказок розгортаються (отримують ${RED}darkstar $(get_path) ${exitStatus}${NONE}), оболонка виконує звичайні розширення, такі як змінні розширення. Ви отримуєте відображається підказку, яке виглядає так \e[1;31mdarkstar PATH 0\e[m. Ніщо на цьому шляху не розширює \eпослідовності до фактичних символів втечі.

При запуску PS1="${RED}\h $(get_path) ${exitStatus}${NONE} ", то PS1змінна встановлюється \e[1;31m\h PATH 0\e[m. Змінні RED, exitStatusі NONEрозширені під час виконання завдання. Тоді підказка містить три оперативні керуючі послідовності ( \e, \hі \eзнову). На цьому етапі немає змінних оболонок, які можна розширити.

Для того, щоб побачити кольори, потрібні змінні кольорів, які містять фактичні символи втечі. Ви можете це зробити так:

RED=$'\033[1;31m'
NONE=$'\033[m'
PS1='\[${RED}\]\h \w $?\[${NONE}\] '

$'…'розширює косо-восьмі послідовності та деякі послідовно-рядкові букви, такі як \n, але не включаючи їх \e. Я зробив три інші зміни до вашого підказки:

  • Використовуйте \[…\]навколо недрукувальних послідовностей, таких як команди, що змінюють колір. В іншому випадку ваш дисплей в кінцевому підсумку зіткнеться, оскільки bash не може визначити ширину підказки.
  • \w це вбудована послідовність аварійного друку для друку поточного каталогу.
  • Вам не потрібно нічого складного, щоб відобразити $?в підказці, якщо у вас це не PROMPT_COMMANDв першу чергу.

Я думаю, що ідея полягала в тому, щоб підказки були зеленими на успіх і червоними на провал.
mattdm

Так, PS1це неправильно, але рада використання $'...'для REDі GREENповинні зробити його роботу з допомогою кендирь - х PS1.
Мікель

1

Спробуйте:

PS1='`exitStatus=$?;if [ $exitStatus -eq 0 ];then echo "\['${GREEN}'\]";else echo "\['${RED}'\]";fi;echo "\h $(get_path) ${exitStatus}${NONE}"`'

1
Дякую, це працює, але чи є спосіб досягти цього, не вкладаючи в підказку if-оператор?
dogbane

1

Ось підхід, з яким я пішов, він уникає використання PROMPT_COMMAND.

# This function is called from a subshell in $PS1,
# to provide a colourised visual indicator of the exit status of the last run command
__COLOURISE_EXIT_STATUS() {
    # uncomment the next line for exit code output after each command, useful for debugging and testing
    #printf -- "\nexit code: $1\n" >&2
    [[ 0 == "$1" || 130 == "$1" ]] && printf -- "$GREEN" || printf -- "$RED"
}

Тоді моя $PS1така:

PS1='# ${debian_chroot:+($debian_chroot)}'"${GREEN}\u${YELLOW}@${DARK_YELLOW}\h${WHITE}:${LIGHT_BLUE}\w${WHITE}\n"'\[$(__COLOURISE_EXIT_STATUS $?)\]# \$'"\[${WHITE}\] "

1
Хоча в цьому конкретному випадку це не має значення, оскільки єдиним значенням $?може бути ціле число, printf '%b' "$GREEN"замість цього ви дійсно повинні використовувати його . Крім того, уникайте використання назв функцій з префіксом __або _як вони використовуються в результаті завершення bash.
nyuszika7h

1

Ось ви йдете - Це працює для мене (TM) в Ubuntu та інших Linuxes (Linuxen?).

Причиною включення виявлення коду виходу $PS1є те, що один хост має $PROMPT_COMMANDнабір лише для читання до зчитування .bashrc.


0

Оскільки PROMPT_COMMAND, чистіше визначити функцію та скористатися цим:

prompt_command() {
    # ...
}
PROMPT_COMMAND=prompt_command
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.