Como canalizar cada comando dado ao shell?

14

Gostaria de editar meu .bashrc para que todos os comandos executados no shell sejam canalizados para algo, por exemplo:

 $ sudo apt update
  _________________
< sudo apt update >
 -----------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||

Eu consegui algo bastante semelhante, mas não inteiramente:

$ bash
$ exec > >(cowsay)
$ echo "Hello AU!"
$ exit
 _______
< Hello AU! >
 -------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||

Não é o resultado desejado, pois só acontece depois de sair do shell atual.

É principalmente para fins de diversão / aprendizado.

M. Becerra
fonte
Usar a -nbandeira para cowsayé útil; isso preserva o espaço em branco.
Wjandrea

Respostas:

12

Você pode adaptar um pouco o seu método. Em vez de canalizar cowsaydiretamente, leia a saída até um caracter delimitante, envie a saída para cowsaye imprima esse caractere após cada comando:

exec > >(while IFS= read -d '' -r line; do if [[ -n $line ]]; then echo; printf "%s\n" "$line" | cowsay; fi; done)
PROMPT_COMMAND='printf "\0"'

Aqui, estou usando o caractere ASCII NUL. Você pode usar outra coisa que dificilmente aparecerá na saída do comando.

Isso será impresso após o prompt, portanto a saída será feia:

$ export LC_ALL=C
$ exec > >(while IFS= read -d '' -r line; do if [[ -n $line ]]; then echo; printf "%s\n" "$line" | cowsay; fi; done)
$ PROMPT_COMMAND='printf "\0"'
$ ls
$
 ______________________________________
/ Desktop Documents Downloads Music    \
| Pictures Public Templates Videos
\ examples.desktop                     /
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

$ echo foo
$
 ______
< foo  >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Observe que isso interromperá qualquer comando que tente saída complexa ou tenha uma interface de usuário de texto (pense em editores de linha de comando, pagers, etc.).

Supondo que você já saiba o que exec > >(...)faz, a parte na substituição do processo é:

  • while IFS= read -d '' -r line; do ... done: esse é um idioma bastante comum para a leitura de dados delimitados pelo caractere ASCII NUL:

    • IFS= define o IFS para a sequência vazia, que desativa a divisão de campos
    • -rimpede o readtratamento \especial na entrada ( \npor exemplo, é lido como \ne não convertido no caractere de nova linha).
    • -d ''é a maneira de dizer readpara ler até o caractere NUL

    Portanto, tudo gira em torno da entrada nas seções delimitadas por NUL, preservando o conteúdo da entrada o máximo possível.

  • if [[ -n $line ]]; then ... fi; done - aja apenas se a entrada lida até o momento não estiver vazia.
  • echo; printf "%s\n" "$line" | cowsay;- imprima uma linha vazia à esquerda, para que a saída do cowsay não colidir com o prompt e envie a entrada lida até agora para o cowsay. printfé mais confiável e seguro do que echo.
muru
fonte
1
Como meu alerta tem uma quebra de linha em que a saída cowsay não colidir com a segunda parte - talvez também definir o prompt para algo não-distrair?
dessert
16

Você pode trapabusar do DEBUGsinal do bash :

trap 'bash -c "$BASH_COMMAND" | cowsay' DEBUG

Exemplo de execução

$ trap 'bash -c "$BASH_COMMAND" | cowsay' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
AU is awesome!

No entanto, isso ainda executará o comando posteriormente. Graças a ilkkachu , encontrei uma maneira de contornar isso:

$ shopt -s extdebug
$ trap 'bash -c "$BASH_COMMAND" | cowsay; false' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
sobremesa
fonte