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

Gilles는 귀하의 주요 문제를 식별했지만 다른 방식으로 설명하려고합니다.

Bash 는 프롬프트에서 변수를 확장 하기 전에특수 프롬프트 이스케이프를 해석 합니다. 즉 , 프롬프트에서 확장 된 변수 를 사용하면 에서 직접 작동하더라도 작동하지 않습니다 .\ePS1

예를 들어, 이것은 예상대로 작동하고 빨간색 텍스트를 제공합니다.

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

그러나 이것은 \e프롬프트에 리터럴 을 넣지 않습니다 .

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

색상 이스케이프를 변수에 저장하려는 경우 ANSI-C 따옴표 ( $'...')를 사용하여 리터럴 이스케이프 문자를 변수에 넣을 수 있습니다.

이렇게하려면, 당신은 당신의 정의를 변경할 수 있습니다 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은 화면에서 프롬프트 길이를 계산할 때 바이트를 무시하도록 요청하는 일부 readline에 해당합니다 . lists.gnu.org/archive/html/bug-bash/2015-08/msg00027.html을 참조하십시오 .
Arthur2e5

무슨 뜻 @ Arthur2e5 할 일이 \]있다 \2? 그리고 그것이 필요한 이유 ${exitStatus}입니까? 내 요점은 ${exitStatus}비 인쇄 문자가 포함되어 있지 않기 때문에 bash는 \[and \]in 없이 프롬프트를 움직이는 문자 수를 올바르게 결정할 수 있어야합니다 \[${exitStatus}\].
Mikel

문제는 색상이 포함되어 있다는 것입니다. (ANSI Escapes)
Arthur2e5

@ Arthur2e5 Ew, 나는 그것을 완전히 놓쳤다. :) 왜 색을 넣을까요? :)
Mikel

1
"Bash는 echo -e가 아니라 PS1에서 echo를 효과적으로 호출하고 있습니다." -잘못되었거나 요점이 없습니다. 강타는 백 슬래시 - 탈출을 같은 확장 않습니다 \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프롬프트 이스케이프 시퀀스입니다. 프롬프트 순서가 확장 된 (yielding ${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, exitStatusNONE할당시 확장됩니다. 그런 다음 메시지가 세 프롬프트 이스케이프 시퀀스를 포함 ( \e, \h, 그리고 \e다시). 이 단계에서 확장 할 쉘 변수는 없습니다.

색상을 보려면 실제 이스케이프 문자를 포함하는 색상 변수가 필요합니다. 이 방법으로 할 수 있습니다 :

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

$'…'백 슬래시-옥탈 시퀀스 및을 \n포함하지 않는 등의 일부 백 슬래시 문자 시퀀스를 확장합니다 \e. 귀하의 프롬프트를 3 가지로 변경했습니다.

  • \[…\]색상 변경 명령과 같은 비 인쇄 시퀀스 주위에 사용하십시오 . 그렇지 않으면 bash가 프롬프트의 너비를 알아낼 수 없으므로 디스플레이가 깨집니다.
  • \w 현재 디렉토리를 인쇄하기위한 내장 이스케이프 시퀀스입니다.
  • 당신이 처음에 $?없는 경우 프롬프트 에 표시하기 위해 복잡한 일이 필요 하지 않습니다 PROMPT_COMMAND.

나는 아이디어가 성공하면 녹색으로, 실패하면 빨간색으로 만드는 것이라고 생각합니다.
mattdm

예, PS1잘못이지만, 사용에 대한 조언 $'...'을 위해 RED그리고 GREEN이 개정 향풀의를 사용하여 작업을해야한다 PS1.
Mikel

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"합니다. 또한 접두사로 사용되는 접두사 __또는 함수 이름을 사용하지 마십시오 _.
nyuszika7h

1

여기 있습니다 -Ubuntu 및 다른 Linux (Linuxen?)의 Works For Me (TM)입니다.

종료 코드 감지를 설정하는 이유는 .bashrc를 읽기 전에 $PS1한 호스트에 읽기 전용 $PROMPT_COMMAND세트가 있기 때문입니다.


0

의 경우 PROMPT_COMMAND함수를 정의하고 사용하는 것이 더 깨끗합니다.

prompt_command() {
    # ...
}
PROMPT_COMMAND=prompt_command
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.