Comment puis-je diriger chaque commande donnée au shell?

14

Je voudrais modifier mon .bashrc afin que chaque commande exécutée sur le shell soit dirigée vers quelque chose, par exemple:

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

J'ai réussi quelque chose d'assez similaire, mais pas entièrement:

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

Ce n'est pas le résultat souhaité, car il ne se produit qu'après avoir quitté le shell actuel.

C'est principalement à des fins de plaisir / d'apprentissage.

M. Becerra
la source
L'utilisation du -ndrapeau pour cowsayest utile; cela lui permet de préserver les espaces blancs.
wjandrea

Réponses:

12

Vous pouvez adapter un peu votre méthode. Au lieu de passer cowsaydirectement à, lisez la sortie jusqu'à un caractère de délimitation, envoyez cette sortie à cowsay, puis imprimez ce caractère après chaque commande:

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

Ici, j'utilise le caractère ASCII NUL. Vous pouvez utiliser autre chose qui n'apparaîtra probablement pas dans la sortie de la commande.

Cela s'imprimera après l'invite, donc la sortie sera moche:

$ 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 |
                ||     ||

Notez que cela cassera toute commande qui essaie une sortie complexe ou qui a une interface utilisateur de texte (pensez aux éditeurs de ligne de commande, aux pagers, etc.).

En supposant que vous savez déjà ce qui se exec > >(...)passe, la partie de la substitution de processus est:

  • while IFS= read -d '' -r line; do ... done: il s'agit d'un idiome assez courant pour lire des données délimitées par le caractère ASCII NUL:

    • IFS= définit l'IFS sur la chaîne vide, ce qui désactive la division des champs
    • -rempêche readde traiter \spécialement l'entrée (ainsi, \npar exemple, est lu comme \net n'est pas converti en caractère de nouvelle ligne).
    • -d ''est la façon de dire readde lire jusqu'à ce que le caractère NUL

    Donc, le tout boucle sur l'entrée dans des sections délimitées par NUL, tout en préservant le contenu de l'entrée autant que possible.

  • if [[ -n $line ]]; then ... fi; done - agir uniquement si l'entrée lue jusqu'à présent n'est pas vide.
  • echo; printf "%s\n" "$line" | cowsay;- imprimer une première ligne vide, afin que la sortie de cowsay ne se heurte pas à l'invite, puis envoyer l'entrée lue jusqu'à présent à cowsay. printfest plus fiable et plus sûr que echo.
muru
la source
1
Comme mon invite a un saut de ligne en elle la sortie cowsay n'affrontement avec la deuxième partie - peut - être mettre l'invite à quelque chose non distrayant?
dessert
16

Vous pouvez trapet abuser du DEBUGsignal de bash :

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

Exemple d'exécution

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

Cependant, cela exécutera toujours la commande par la suite. Grâce à ilkkachu, j'ai trouvé un moyen de contourner cela:

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