Bash: exibe o status de saída no prompt:

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)'

A seguir, aparece a saída correta do status, mas as variáveis de cor não são expandidas:

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

No entanto, o abaixo, me fornece as cores, mas o status de saída não é atualizado:

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

Qual é o caminho certo para fazer isso? Como posso consertar isso para que o exitStatus e as cores funcionem?

    
por dogbane 01.03.2011 / 15:49

6 respostas

8

Gilles identificou seu problema principal, mas eu queria tentar explicá-lo de maneira diferente.

O Bash interpreta o aviso especial que escapa somente antes expandindo quaisquer variáveis no prompt. Isso significa que usar \e em uma variável que é expandida a partir do prompt não funciona, embora funcione diretamente em PS1 .

Por exemplo, isso funciona como esperado e fornece um texto em vermelho:

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

Mas isso não acontece, apenas coloca um literal \e no prompt:

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

Se você quiser armazenar as fugas de cor nas variáveis, você pode usar aspas ANSI-C ( $'...' ) para colocar um caractere de escape literal na variável.

Para fazer isso, você pode alterar sua definição de GREEN , RED e NONE , de modo que seu valor seja a sequência de escape real.

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

Se você fizer isso, seu primeiro PS1 com aspas simples deverá funcionar:

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

No entanto, você terá um segundo problema.

Tente executá-lo, pressione Seta para cima , depois Início , e o cursor não voltará ao início da linha.

Para corrigir isso, altere PS1 para incluir \[ e \] em torno das seqüências de escape de cores, por exemplo,

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

Você não pode usar get_exit_status corretamente aqui, pois sua saída contém os caracteres de impressão (o código de saída) e não-impressão (os códigos de cores) e não há como marcá-lo corretamente no prompt. Colocar \[...\] marcaria como não impressa na íntegra, o que não está correto. Você terá que alterar a função para que ela imprima apenas o código de cor apropriado e, em seguida, coloque-a com \[...\] no prompt.

    
por 03.03.2011 / 03:16
3

Quando você executa PS1='${RED}\h $(get_path) ${exitStatus}${NONE} ' , a variável PS1 é definida como ${RED}\h $(get_path) ${exitStatus}${NONE} , onde apenas \h é uma sequência de escape de prompt. Após as sequências de prompt são expandidas (rendendo ${RED}darkstar $(get_path) ${exitStatus}${NONE} ), o shell executa as expansões usuais, como expansões variáveis. Você recebe um prompt exibido que parece com \e[1;31mdarkstar PATH 0\e[m . Nada ao longo do caminho expande as sequências de \e para caracteres de escape reais.

Quando você executa PS1="${RED}\h $(get_path) ${exitStatus}${NONE} " , a variável PS1 é definida como \e[1;31m\h PATH 0\e[m . As variáveis RED , exitStatus e NONE são expandidas no momento da atribuição. Em seguida, o prompt contém três seqüências de escape de prompt ( \e , \h e \e novamente). Não há variáveis de shell para expandir neste estágio.

Para ver as cores, você precisa das variáveis de cor para conter os caracteres de escape reais. Você pode fazer assim:

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

$'…' expande seqüências de backslash-octal e algumas sequências de barra invertida, como \n , mas não inclui \e . Fiz outras três alterações no seu prompt:

  • Use \[…\] em torno de sequências não impressas, como comandos de mudança de cor. Caso contrário, seu display acabará distorcido porque o bash não consegue descobrir a largura do prompt.
  • \w é uma seqüência de escape interna para imprimir o diretório atual.
  • Você não precisa de nada complicado para mostrar $? no prompt se você não tiver um PROMPT_COMMAND em primeiro lugar.
por 03.03.2011 / 01:14
1

Tente:

PS1=''exitStatus=$?;if [ $exitStatus -eq 0 ];then echo "\['${GREEN}'\]";else echo "\['${RED}'\]";fi;echo "\h $(get_path) ${exitStatus}${NONE}"''
    
por 01.03.2011 / 16:18
1

Aqui está a abordagem que eu escolhi, evita o uso de 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"
}

Então meu $PS1 é o seguinte:

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

Aqui você vai - Isso funciona para mim (TM) no Ubuntu e outros Linuxes (Linuxen?).

O motivo para colocar a detecção do código de saída em $PS1 é que um host tem um conjunto $PROMPT_COMMAND de somente leitura antes que o .bashrc seja lido.

    
por 01.03.2011 / 16:18
0

Para PROMPT_COMMAND , é mais limpo definir uma função e usar isso:

prompt_command() {
    # ...
}
PROMPT_COMMAND=prompt_command
    
por 12.06.2014 / 19:11

Tags