Ofereço este post com conteúdo útil como sacrifício aos leitores, de modo a ter crédito para escrever posts reclamando da vida mais tarde.
O prompt padrão do bash na maior parte das distribuições de GNU/Linux costuma ser algo do tipo username@hostname diretório$ . Esse prompt pode ser customizado alterando-se o valor das variáveis PS1 ("prompt string 1") e companhia:
vitor@eukleides ~$ PS1='oi? ' oi? pwd /home/vitor oi?
Você pode experimentar prompts diferentes alterando essa variável até achar um que seja do seu agrado, e então alterar um dos arquivos de configuração do bash (e.g., ~/.bashrc) para setar a variável para o valor desejado na inicialização do shell.
Como você pode imaginar, o conteúdo de PS1 não precisa ser texto estático. O bash substitui certas seqüências de \ seguido de um caractere (e.g., \u) na definição do prompt por valores específicos (e.g., o nome do usuário). O prompt padrão apresentado acima pode ser obtido pela string \u@\h \W\$ :
Uma lista completa das seqüências expandidas pelo bash no prompt pode ser obtida procurando por PROMPTING no manual (man bash). Outras seqüências úteis incluem \w (caminho completo do diretório atual) e \! (número do comando atual no histórico; útil para quem gosta de usar os comandos de recuperação do histórico, e.g., !42 para reexecutar o comando de número 42).
Uma das maravilhas do terminal (que talvez seja digna de um post a respeito no futuro) são as escape sequences: seqüências de caracteres especiais que podem produzir toda sorte de firula, desde cores e outros efeitos de texto até alterações no título da janela de terminal. Por exemplo, a seqüência ESC [ 3 número m, onde ESC é o caractere ASCII número 27, seleciona a cor de texto com o número especificado (que varia de 0 a 7); a seqüência ESC [ 0 m retorna as cores e outros atributos para seus valores padrão. O caractere ESC pode ser representado no prompt pela seqüência \e. Assim:
PS1='\e[34m\u@\h \W\$ \e[0m'
lhe dará um prompt idêntico ao padrão, mas em azul. Existe uma manpage (man console_codes) com uma lista de seqüências ESC suportadas por diversos terminais.
Só tem um problema: o bash usa o tamanho da string de prompt expandida para calcular o tamanho que o prompt ocupa na tela; ele precisa dessa informação para determinar onde ocorre a quebra de linha, caso o comando digitado possua mais de uma linha, e para saber onde posicionar o cursor caso você tecle Home, entre outras coisas. O problema é que os caracteres de uma seqüência ESC não ocupam espaço na tela, mas aumentam o tamanho da prompt string. Para o bash poder calcular corretamente o tamanho do prompt, é necessário demarcar os trechos de seqüências ESC no prompt entre \[ e \]:
PS1='\[\e[34m\]u@\h \W\$ \[\e[0m\]'
Provavelmente a coisa mais útil que se costuma fazer com seqüências ESC no prompt é setar o título da janela de terminal para conter o diretório atual:
PS1='\[\e]0;\w\a\]\u@\h \W\$ '
ESC ] 0 ; título BEL é a seqüência que muda o título da janela do xterm e outros terminais gráficos. (BEL, representado no prompt por \a, é o caractere ASCII número 7; em situações normais, ele é o caractere que faz o terminal emitir um beep.)
Se você nem sempre acessa o terminal via interface gráfica, pode ser uma boa idéia testar se o terminal atual é gráfico antes de adicionar seqüências ESC no prompt:
case "$TERM" in xterm*|gnome*|konsole*) PS1='\[\e]0;\w\a\]\u@\h \W\$ ' ;; *) PS1='\u@\h \W\$ ' ;; esac
Ou, alternativamente, para evitar duplicação:
# Primeiro adiciona a seqüência ESC. case "$TERM" in xterm*|gnome*|konsole*) PS1='\[\e]0;\w\a\]' ;; *) PS1='' ;; esac # Depois, o resto do prompt (igual em ambos os casos). PS1+='\u@\h \W\$ '
Além de backslash sequences, o bash substitui variáveis presentes na prompt string. Por exemplo, PS1='$USER@$HOSTNAME $PWD\$ ' tem mais ou menos o mesmo efeito que PS1='\u@\h \w\$ '. Ao se usar variáveis no prompt, é importante usar aspas simples em volta do valor que está sendo atribuído a PS1:
O bash também expande comandos (usando a sintaxe $(comando) ou `comando`) presentes na string de prompt. Novamente, é importante cuidar para usar aspas simples caso se queira que o comando execute toda vez que o prompt é impresso, e não apenas uma vez durante a definição do prompt. De modo geral, executar um comando (criar um processo) cada vez que o prompt é impresso não me parece uma boa idéia; normalmente, executar o comando uma vez só resolve a maior parte dos problemas e é menos custoso computacionalmente. (Se bem que hoje em dia criar um processo provavelmente não vai fazer uma diferença palpável na execução do shell ou do sistema; eu recomendaria não fazer isso com o prompt do root, entretanto. A gente nunca sabe quando vai ter que matar uma fork bomb ou um processo mal-comportado no sistema.)
Uma utilidade de usar variáveis e/ou comandos é incluir nome da tty atual no prompt. Isso é particularmente útil quando se está trabalhando no modo texto, pois pelo nome da tty sabe-se o número do console virtual (e lembrando o número pode-se rapidamente voltar para o console em questão teclando Alt-Fn).
tty="$(tty)" # Recupera o nome completo da tty (e.g., /dev/tty1) if [[ $tty == */pts/* ]]; then ttybase="pts${tty##*/}" # Transforma /dev/pts/0 em pts0 else ttybase="${tty##*/}" # Transforma /dev/tty1 em tty1 fi PS1='\u@$ttybase \W\$ ' # Usa o nome da tty ao invés do hostname.
Ganhamos o nome da tty, mas perdemos o hostname. Uma possibilidade é testar se a conexão atual é via ssh, e usar o hostname nesse caso:
tty="$(tty)" if [[ $SSH_CONNECTION ]]; then ttybase="$HOSTNAME" elif [[ $tty == */pts/* ]]; then ttybase="pts${tty##*/}" else ttybase="${tty##*/}" fi PS1='\u@$ttybase \W\$ '
Outra informação útil de se incluir no prompt (uma que eu já não consigo viver sem, a ponto de alterar o prompt de outras máquinas quando vou usá-las por mais do que alguns minutos) é o exit status do último comando. O exit status é um valor ente 0 e 255 que cada processo retorna ao terminar. (É por isso que a main() retorna int, e não void, em C.) Por convenção, um programa retorna 0 se foi bem-sucedido, e um valor diferente de zero caso tenha ocorrido um erro (valores diferentes podem ser usados para erros diferentes). O exit status do último comando vive na pseudo-variável $?:
PS1='\u@$ttybase \W($?)\$ '
A presença do exit status no prompt é útil por mil razões. Primeiro, se você costuma escrever shell scripts, freqüentemente deseja saber que valor um comando retorna em certa situação. Além disso, o exit status presente no prompt dá um feedback imediato quanto ao sucesso ou falha do último comando, sem ter que ler toda a saída do comando. Por exemplo, ao copiar um diretório com muitos arquivos com cp -v, pode ser que uma mensagem de erro passe desapercebida no meio da saída normal do cp; com o exit status no prompt, o erro é imediatamente visível. Com o tempo, verificar o exit status é um ato inconsciente; para mim, hoje em dia, ele é um feedback tão importante quanto a saída do comando. Finalmente, existem alguns programas cretinos que não imprimem mensagens de erro, apenas retornam 1 para indicar que falharam. (Lamentavelmente, com o exit status no prompt, você possivelmente se sentirá inclinado a escrever programas que fazem o mesmo. Eu não tenho o direito de atirar pedras.)
A última maravilha promptística que tenho a apresentar é a variável PROMPT_COMMAND: se essa variável for setada, seu valor é interpretado como um comando a ser executado antes de imprimir o prompt. Você pode usá-la para chamar alguma função que seta uma variável usada na string do prompt.
Eis uma possibilidade: nos doces tempos do bash 1.14, o comportamento do \W era diferente: não havia abreviação do diretório home para ~; além disso, se o diretório estivesse diretamente abaixo do raiz (e.g., /mnt), o bash imprimia a / no início do nome, e não apenas mnt. O comportamento mudou no bash 2, e me foi a mi mui mal. Felizmente, é possível corrigir esse problema usando o PROMPT_COMMAND e uma variável no prompt:
reduced_pwd() { case "$PWD" in /*/*) REDPWD="${PWD##*/}" ;; *) REDPWD="$PWD" ;; esac } PROMPT_COMMAND="reduced_pwd" PS1='\u@$ttybase $REDPWD($?)\$ '
Pode-se adaptar a reduced_pwd, com uma pequena dose de falcatrua, para mostrar os últimos dois itens do diretório atual, ao invés do caminho completo ou do último item:
reduced_pwd() { local prefix case "$PWD" in /*/*/*) # Se PWD = /mnt/foo/bar/baz/quux: prefix="${PWD%/*/*}" # prefix = /mnt/foo/bar REDPWD="${PWD#"$prefix"/}" # REDPWD = baz/quux ;; *) REDPWD="$PWD" ;; esac }
Pode-se obter a temperatura da CPU, ou a carga da bateria da máquina, a partir dos arquivos em /sys. Pode-se baixar periodicamente informação climática de algum site e adicionar a temperatura ao prompt, mudando a cor dependendo de se o tempo está ensolarado ou nublado ou chuvoso. As possibilidades são infinitas.
Copyright © 2010-2024 Vítor De Araújo
O conteúdo deste blog, a menos que de outra forma especificado, pode ser utilizado segundo os termos da licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
Powered by Blognir.