Jak potokować każde polecenie przekazane powłoce?

14

Chciałbym edytować mój plik .bashrc, aby każde polecenie wykonywane w powłoce zostało potokowane do czegoś, na przykład:

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

Udało mi się zrobić coś podobnego, ale nie do końca:

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

Nie jest to pożądany wynik, ponieważ dzieje się to dopiero po wyjściu z bieżącej powłoki.

Przeznaczony jest głównie do zabawy / nauki.

M. Becerra
źródło
Przydatne jest użycie -nflagi cowsay; dzięki temu zachowuje białe znaki.
wjandrea

Odpowiedzi:

12

Możesz nieco dostosować swoją metodę. Zamiast cowsaybezpośrednio potokować, odczytuj dane wyjściowe do znaku ograniczającego, wyślij dane wyjściowe do cowsay, a następnie wydrukuj ten znak po każdym poleceniu:

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

Tutaj używam znaku ASCII NUL. Możesz użyć czegoś innego, co prawdopodobnie nie pojawi się w wynikach poleceń.

Zostanie to wydrukowane po monicie, więc wynik będzie brzydki:

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

Zauważ, że spowoduje to uszkodzenie dowolnego polecenia, które próbuje skomplikowanych danych wyjściowych lub ma tekstowy interfejs użytkownika (pomyśl edytory wiersza poleceń, pagery itp.).

Zakładając, że już wiesz, co exec > >(...)robi, częścią podstawienia procesu jest:

  • while IFS= read -d '' -r line; do ... done: jest to dość powszechny idiom do odczytu danych ograniczonych znakiem NUL ASCII:

    • IFS= ustawia IFS na pusty ciąg, co wyłącza dzielenie pól
    • -rzapobiega specjalnemu readtraktowaniu \danych wejściowych ( \nna przykład jest odczytywany jako \nznak nowej linii i nie jest do niego konwertowany).
    • -d ''to sposób, readaby czytać do znaku NUL

    Całość zapętla się nad danymi wejściowymi w sekcjach rozdzielanych przez NUL, zachowując jednocześnie możliwie jak najwięcej zawartości danych wejściowych.

  • if [[ -n $line ]]; then ... fi; done - działają tylko wtedy, gdy odczyt odczytany do tej pory nie jest pusty.
  • echo; printf "%s\n" "$line" | cowsay;- wypisz wiodącą pustą linię, aby wynik cowsay nie kolidował z pytaniem, a następnie wyślij dane wejściowe do tej pory do cowsay. printfjest bardziej niezawodny i bezpieczniejszy niż echo.
muru
źródło
1
Jak mój wiersz ma LINEBREAK w nim wyjście cowsay nie kolidować z drugiej strony - może to również ustawić monit o czymś nie rozpraszać?
deser
16

Możesz trapi wykorzystuj DEBUGsygnał bash :

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

Przykładowy przebieg

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

Jednak nadal będzie to wykonywać polecenie później. Dzięki ilkkachu znalazłem sposób na obejście tego:

$ shopt -s extdebug
$ trap 'bash -c "$BASH_COMMAND" | cowsay; false' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
deser
źródło