Wie leite ich jeden Befehl an die Shell weiter?

14

Ich möchte meine .bashrc-Datei so bearbeiten, dass jeder auf der Shell ausgeführte Befehl an eine bestimmte Adresse weitergeleitet wird. Beispiel:

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

Ich habe etwas ziemlich Ähnliches geschafft, aber nicht ganz:

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

Dies ist nicht das gewünschte Ergebnis, da dies erst nach dem Verlassen der aktuellen Shell erfolgt.

Es ist hauptsächlich für Spaß / Lernzwecke.

M. Becerra
quelle
Es ist nützlich, die -nFlagge zu verwenden cowsay. Dadurch bleibt das Leerzeichen erhalten.
wjandrea

Antworten:

12

Sie können Ihre Methode ein wenig anpassen. Anstatt cowsaydirekt an weiterzuleiten, lesen Sie die Ausgabe bis zu einem Begrenzungszeichen, senden Sie diese Ausgabe an cowsayund drucken Sie dieses Zeichen nach jedem Befehl aus:

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

Hier verwende ich das ASCII-NUL-Zeichen. Sie können etwas anderes verwenden, das in der Befehlsausgabe wahrscheinlich nicht enthalten ist.

Dies wird nach der Eingabeaufforderung gedruckt, so dass die Ausgabe hässlich ist:

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

Beachten Sie, dass dies jeden Befehl unterbricht, der eine komplexe Ausgabe versucht oder eine Textbenutzeroberfläche hat (denken Sie an Befehlszeileneditoren, Pager usw.).

Vorausgesetzt, Sie wissen bereits, was exec > >(...)passiert, ist der Teil der Prozessersetzung:

  • while IFS= read -d '' -r line; do ... done: Dies ist eine ziemlich verbreitete Redewendung zum Lesen von Daten, die durch das ASCII-NUL-Zeichen begrenzt sind:

    • IFS= Setzt das IFS auf die leere Zeichenfolge, wodurch die Feldaufteilung deaktiviert wird
    • -rverhindert read, dass \die Eingabe speziell behandelt wird (wird also \nbeispielsweise gelesen \nund nicht in das Zeilenumbruchzeichen konvertiert).
    • -d ''ist der Weg zu sagen read, bis das NUL-Zeichen zu lesen

    Das Ganze durchläuft also die Eingabe in durch NUL getrennten Abschnitten, wobei der Inhalt der Eingabe so weit wie möglich erhalten bleibt.

  • if [[ -n $line ]]; then ... fi; done - nur dann handeln, wenn der bisher gelesene Eingang nicht leer ist.
  • echo; printf "%s\n" "$line" | cowsay;- Eine führende leere Zeile ausgeben, damit die Ausgabe von cowsay nicht mit der Eingabeaufforderung kollidiert, und dann die bis dahin gelesene Eingabe an cowsay senden. printfist zuverlässiger und sicherer als echo.
muru
quelle
1
Da meine Eingabeaufforderung einen Zeilenumbruch enthält, kollidiert die Ausgabe von cowsay mit dem zweiten Teil der Eingabeaufforderung. Stellen Sie die Eingabeaufforderung möglicherweise auch auf etwas ein, das nicht ablenkt.
Dessert
16

Sie können trapdas DEBUGSignal der Bash missbrauchen :

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

Beispiellauf

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

Dadurch wird der Befehl jedoch weiterhin ausgeführt. Dank ilkkachu habe ich einen Weg gefunden, das zu umgehen :

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