AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / ubuntu / Perguntas / 1504292
Accepted
reneas
reneas
Asked: 2024-02-22 02:45:01 +0800 CST2024-02-22 02:45:01 +0800 CST 2024-02-22 02:45:01 +0800 CST

Como posso fazer um prompt do bash corretamente com cores de erro e emoji?

  • 772

Depois de resolver o primeiro problema com meu prompt personalizado, ainda tenho outro.

Quando eu percorro meus últimos comandos usados ​​por meio das teclas de seta para cima e para baixo, às vezes alguns caracteres de um comando anterior permanecem visíveis, embora não estejam acessíveis nem estejam realmente na linha de comando. Eles são apenas um bug visual muito chato e confuso.

Se parece com isso:
insira a descrição da imagem aqui

Aqui subi um pouco no histórico de comandos e depois voltei ao prompt atual (vazio) e digitei echo. o pip i(vindo de um pip installcomando anterior) não está acessível com meu cursor. É visível lá, mas na verdade não existe.

Meu .bashrctem este código para personalizar o prompt:

set_PS1()
{
    local Reset="\\[$(tput sgr0 )\\]"
    local Bold="\\[$(tput bold )\\]"
    local Red="\\[$(tput setaf 1 )\\]"
    local Green="\\[$(tput setaf 2 )\\]"
    local Yellow="\\[$(tput setaf 3 )\\]"
    local Blue="\\[$(tput setaf 4 )\\]"
    local MagentaBG="\\[$(tput setab 5 )\\]"
    local Cyan="\\[$(tput setaf 6 )\\]"

    local Whoami='\u'
    local Where='\w'
    local Hostname='\h'
    local Time='\D{%H:%M:%S}'
    local Exit_Code="$?"

    exit_code_prompt() {
        local Exit_Code="$?"
        local Red="$(tput setaf 1 )"
        local Green="$(tput setaf 2 )"
        if (($Exit_Code == 0 )); then
            printf '%s\xE2\x9C\x93 \xE2\x86\x92 ' "$Green" # Green checkmark symbol
        else
            printf '%s\xE2\x9C\x98 %s \xE2\x86\x92 ' "$Red" "$Exit_Code" # Red cross mark symbol and exit code
        fi
    }

    local Line_1="$Bold$Yellow$Time $Cyan$Whoami$Blue@$Cyan$Hostname$Reset$Bold":" $Blue$Where$Reset"
    local Line_2="$Bold\$(exit_code_prompt)$Reset$Bold \$: $Reset"
    #local Line_2="$Bold \$: $Reset"

    PS1="$Line_1\n$Line_2"

    unset -f set_PS1
}

set_PS1

Já reduzi o problema à exit_code_promptfunção, pois o problema não aparece se eu removê-lo do$Line_2

EDIT: Quando coloco as definições de cores dentro da função entre colchetes, como na parte externa, assim:

exit_code_prompt() {
        local Exit_Code="$?"
        local Red="\\[$(tput setaf 1 )\\]"
        local Green="\\[$(tput setaf 2 )\\]"
        if (($Exit_Code == 0 )); then
            printf '%s\xE2\x9C\x93 \xE2\x86\x92 ' "$Green" # Green checkmark symbol
        else
            printf '%s\xE2\x9C\x98 %s \xE2\x86\x92 ' "$Red" "$Exit_Code" # Red cross mark symbol and exit code
        fi
    }

Eu obtenho este resultado:

insira a descrição da imagem aqui
O mesmo resultado se eu colocar apenas barras invertidas. \
Além disso, o problema inicial ainda está lá!

command-line
  • 1 1 respostas
  • 877 Views

1 respostas

  • Voted
  1. Best Answer
    Daniel T
    2024-02-22T04:35:30+08:002024-02-22T04:35:30+08:00

    Nova solução

    Acontece que é realmente possível fazer isso com just PS1e not PROMPT_COMMAND. Não precisamos definir nenhuma variável global adicional. Aqui está uma frase:

    PS1=$'\e[1;33m\\t \e[36m\u\e[34m@\e[36m\h\e[;1m: \e[34m\w\n \[\b\e[;1;31m✘\] ${?/#0/\[\b\b\e[32m✓ \]}${?/#[1-9]*/ }\[\b→\e[;1m\] \$: \[\e[m\]'

    As melhorias da minha solução original abaixo são as seguintes:

    • Apenas a última linha precisa\[\]
    • Eu expandi tputpara \e[...m. Isso é compatível com o Ubuntu e não é uma preocupação porque a cor padrão .bashrctambém faz isso
    • Colapso sucessivo \e[Xm\e[Ymem \e[X;Ym, e o negrito anterior nem sempre precisa ser redefinido
    • \D{%H:%M:%S}=\\t
    • Sequências desconhecidas \Xnão precisam de escape de barra invertida
    • Confio em $?ser 0ou positivo sem zeros à esquerda: ?/#0*/=?/#0/
    • ${?/#[1-9]*/ }\[\binsere um espaço, depois qualquer caractere (atualmente espaço) para diferente de zero e qualquer caractere (atualmente 0) para zero. Em seguida, o caractere adicional é excluído, para implementar a inserção de exatamente um espaço apenas para valores diferentes de zero.
    • [1-9]*é um glob que significa qualquer dígito de 1 a 9 e qualquer coisa, não um RegEx que significa qualquer número do anterior
    • ✘\] ${?/#0/\[\b\b\e[32m✓ \]}sempre imprime primeiro o símbolo da cruz vermelha. Se for zero, voltamos e substituímos por uma marca de seleção verde. Se for diferente de zero, imprimiremos o código de erro

    Solução guiada

    Aqui está um prompt de trabalho:

    set_PS1() {
        local Exit_Code="$?"
        local Reset="\\[$(tput sgr0 )\\]"
        local Bold="\\[$(tput bold )\\]"
        local Red="\\[$(tput setaf 1 )\\]"
        local Green="\\[$(tput setaf 2 )\\]"
        local Yellow="\\[$(tput setaf 3 )\\]"
        local Blue="\\[$(tput setaf 4 )\\]"
        local MagentaBG="\\[$(tput setab 5 )\\]"
        local Cyan="\\[$(tput setaf 6 )\\]"
    
        local Whoami='\u'
        local Where='\w'
        local Hostname='\h'
        local Time='\D{%H:%M:%S}'
        # Emoji are multi-byte, but shells think 1 byte = 1 character
        # We add a 1-character space, then enable color-code mode to ignore
        # the upcoming emoji, then backspace to draw the emoji on top of the space.
        local emoji_start=$' \\[\b'
        local emoji_end=$'\\]'
    
        if (($Exit_Code == 0 )); then
            local exit_code_prompt="$Green$emoji_start"$'\xE2\x9C\x93'"$emoji_end" # Green checkmark symbol
        else
            local exit_code_prompt="$Red$emoji_start"$'\xE2\x9C\x98'"$emoji_end $Exit_Code" # Red cross mark symbol and exit code
        fi
    
    
        local Line_1="$Bold$Yellow$Time $Cyan$Whoami$Blue@$Cyan$Hostname$Reset$Bold":" $Blue$Where$Reset"
        local Line_2="$Bold$exit_code_prompt $emoji_start"$'\xE2\x86\x92'"$emoji_end$Reset$Bold \\$: $Reset"
        #local Line_2="$Bold \$: $Reset"
    
        PS1="$Line_1\\n$Line_2"
    }
    
    # We need to expand exit_code_prompt BEFORE PS1 prompt string expansion (see shopt promptvars in man bash)
    # so we want to move it to PROMPT_COMMAND which runs earlier.
    PROMPT_COMMAND=set_PS1
    
    • PS1sofre expansão imediata e depois substituição, então precisamosPROMPT_COMMAND
    • Isso vaza o set_PS1global, mas você já exit_code_promptvazou o global
    • "\$"precisa ser "\\$"assim, passa por avaliação imediata em vez de imediatamente
    • Emojis são multibyte e também precisam ser agrupados, exceto que desta vez precisamos inserir um espaço falso porque eles têm 1 caractere de largura, ao contrário dos códigos de cores de 0 caracteres.
    • printfé desnecessariamente complicado quando você poderia simplesmente fazer$''

    Agora ↑/ ↓o histórico de comandos funciona. Rolar um prompt multilinha com Ctrl+ ←/ →também salta para a posição correta agora.

    aqui estão alguns exemplos:

    • Demonstração imediata:

      demonstração imediata

    • Sequência longa:

      corda longa

    • String longa então Ctrl+ ←:

      string longa então ←

    • pip installentão echo:

      pip instalar e depois ecoar

    • echoentão ↑na história:

      eco então ↑ na história

    • 9

relate perguntas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Existe um comando para listar todos os usuários? Também para adicionar, excluir, modificar usuários, no terminal?

    • 9 respostas
  • Marko Smith

    Como excluir um diretório não vazio no Terminal?

    • 4 respostas
  • Marko Smith

    Como descompactar um arquivo zip do Terminal?

    • 9 respostas
  • Marko Smith

    Como instalo um arquivo .deb por meio da linha de comando?

    • 11 respostas
  • Marko Smith

    Como instalo um arquivo .tar.gz (ou .tar.bz2)?

    • 14 respostas
  • Marko Smith

    Como listar todos os pacotes instalados

    • 24 respostas
  • Martin Hope
    Flimm Como posso usar o docker sem sudo? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    led-Zepp Como faço para salvar a saída do terminal em um arquivo? 2014-02-15 11:49:07 +0800 CST
  • Martin Hope
    ubuntu-nerd Como descompactar um arquivo zip do Terminal? 2011-12-11 20:37:54 +0800 CST
  • Martin Hope
    TheXed Como instalo um arquivo .deb por meio da linha de comando? 2011-05-07 09:40:28 +0800 CST
  • Martin Hope
    Ivan Como listar todos os pacotes instalados 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    David Barry Como determino o tamanho total de um diretório (pasta) na linha de comando? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher "Os seguintes pacotes foram retidos:" Por que e como resolvo isso? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford Como os PPAs podem ser removidos? 2010-07-30 01:09:42 +0800 CST

Hot tag

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve