Befehl in Ausgabedatei aufnehmen?

17

Entschuldigung für den verwirrenden Titel!

Angenommen, ich renne

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

Ich erhalte eine Datei mit dem Namen "kwin-dependant" in meinem Desktop-Ordner.

Gibt es einen Trick, um den Befehl, den ich als Teil der Datei ausgegeben habe, vorzugsweise am Anfang der Datei einzuschließen?

Zumindest in 14.04 LTS würden die ersten paar Zeilen so aussehen:

apt-cache depends kde-window-manager > ~/Desktop/kwin-depends

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>

Statt einfach so:

kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
Gerechtigkeit für Monica
quelle
3
Da es mittlerweile viele andere gute und flexible Lösungen gibt, sollten Sie in Erwägung ziehen, die Antwort, die vorschlägt, den Befehl manuell in die Datei zu schreiben, durch zweimaliges Eingeben zu ignorieren und stattdessen eine der vielseitigen Lösungen zu akzeptieren.
Byte Commander

Antworten:

18

Ich würde nur eine einfache Funktion verwenden. Fügen Sie dies zu Ihrer ~/.bashrcDatei hinzu:

function runcom(){
    echo "$@"
    ## Run the command
    $@
}

Wenn Sie jetzt einen Befehl ausführen und ausdrucken möchten, können Sie Folgendes tun:

runcom apt-cache depends kde-window-manager > out

Das Obige erzeugt diese Datei:

$ cat out
apt-cache depends kde-window-manager
kde-window-manager
  Depends: perl
  Depends: kde-runtime
  Depends: kde-style-oxygen
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
    libegl1-mesa
  Depends: libgcc1
 |Depends: libgl1-mesa-glx
  Depends: <libgl1>
    libgl1-mesa-swx11
    libgl1-mesa-glx
 |Depends: libgles2-mesa
  Depends: <libgles2>
    libgles2-mesa
  Depends: libice6
  Depends: libkactivities6
  Depends: libkcmutils4
  Depends: libkdeclarative5
  Depends: libkdecorations4abi2
  Depends: libkdecore5
  Depends: libkdeui5
  Depends: libkio5
  Depends: libknewstuff3-4
  Depends: libkwineffects1abi5
  Depends: libkwinglesutils1
  Depends: libkwinglutils1abi2
  Depends: libkworkspace4abi2
  Depends: libplasma3
  Depends: libqt4-dbus
  Depends: libqt4-declarative
  Depends: libqt4-script
  Depends: libqtcore4
  Depends: libqtgui4
  Depends: libsm6
  Depends: libstdc++6
  Depends: libwayland-client0
 |Depends: libwayland-egl1-mesa
  Depends: <libwayland-egl1>
    libwayland-egl1-mesa
  Depends: libx11-6
  Depends: libx11-xcb1
  Depends: libxcb-composite0
  Depends: libxcb-damage0
  Depends: libxcb-image0
  Depends: libxcb-keysyms1
  Depends: libxcb-randr0
  Depends: libxcb-render0
  Depends: libxcb-shape0
  Depends: libxcb-shm0
  Depends: libxcb-sync1
  Depends: libxcb-xfixes0
  Depends: libxcb-xtest0
  Depends: libxcb1
  Depends: libxcursor1
  Depends: libxext6
  Depends: libxrandr2
  Depends: libxxf86vm1
  Breaks: kde-style-bespin
  Breaks: kde-style-bespin:i386
  Breaks: <kde-style-skulpture>
  Breaks: <kde-style-skulpture:i386>
  Breaks: kde-workspace-data
  Breaks: <kde-workspace-data:i386>
  Breaks: kdeartwork-theme-window
  Breaks: kdeartwork-theme-window:i386
  Breaks: <kdebase-workspace-data>
  Breaks: <kdebase-workspace-data:i386>
  Breaks: kwin-style-crystal
  Breaks: kwin-style-crystal:i386
  Breaks: kwin-style-dekorator
  Breaks: kwin-style-dekorator:i386
  Breaks: kwin-style-qtcurve
  Breaks: kwin-style-qtcurve:i386
  Replaces: kde-workspace-data
  Replaces: <kde-workspace-data:i386>
  Replaces: <kdebase-workspace-data>
  Replaces: <kdebase-workspace-data:i386>
  Conflicts: kde-window-manager:i386
terdon
quelle
Ich möchte die Torpfosten nicht hierher verschieben, aber gibt es eine Möglichkeit, Ihren Code dazu zu bringen, auch Aliase zu akzeptieren? Wenn ich apt-cache dependszum Beispiel einen Alias für habe acd, erhalte ich beim Ausführen "Kein Befehl 'acd' gefunden, meinten Sie: ..." runcom acd leafpad > out.
Gerechtigkeit für Monica
@DKBose-Aliase werden in der .bashrc-Datei und nicht in der Shell definiert, und Funktionen rufen nur die Binärdateien auf, die sich unter der Variablen $ PATH befinden. Aber Sie können einen einfachen Trick machen. Zum Beispiel lsist ls --color=auto' in der Realität aliasiert . Was Sie tun können (solange es keine einzelne oder doppelte Anführungszeichen in Ihrem Alias ist), dann ist dies: $ terdonsFunction $(alias ls | awk -F '=' '{$1="";print}'| tr "'" " ") .
Sergiy Kolodyazhnyy
ODER verwandeln Sie Ihren Befehl in eine Variable. Wie ich schon in meiner Antwort gezeigt habe. MYCOMMAND="apt-cache depends"; terdonsFunction $MYCOMMAND leafpad > out.txt
Sergiy Kolodyazhnyy
@ Serg, siehe GARCIN Davids Antwort: askubuntu.com/a/688936/248158
Gerechtigkeit für Monica
Dies ist die "offensichtliche" Antwort und funktioniert hervorragend, es sei denn, eines der Argumente beinhaltet Code, der ausgeführt wird und Nebenwirkungen hat, die sich ansammeln können. Dies ist ein Randfall, sodass er nicht sehr häufig auftritt.
Joe
11

Du kannst tun:

tee file.txt <<<'apt-cache depends kde-window-manager' | bash >>file.txt

Das Gleiche mit echoanstelle von Here strings ( <<<):

echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt
  • tee schreibt in STDOUT und auch in die Datei file.txt

  • Der STDOUT von teeie apt-cache depends kde-window-managerwird eingespeist, bashum den Befehl auszuführen und den STDOUT anzufügen file.txt.

Beispiel:

$ echo 'apt-cache depends kde-window-manager' | tee file.txt | bash >>file.txt

$ cat file.txt 
apt-cache depends kde-window-manager
kde-window-manager
  Depends: kde-runtime
  Depends: libc6
 |Depends: libegl1-mesa
  Depends: <libegl1-x11>
heemayl
quelle
1
Gute Antwort! Einfach und auf den Punkt! Ich habe es mit einem versucht, teeaber meiner ist immer wieder gescheitert. Gut gemacht! +1
Terrance
@Seth Ich habe auch darüber nachgedacht, mit den Dateideskriptoren zu spielen, aber es teescheint ordentlich :)
heemayl
11

Am minimalistischsten - Ansatz Nr. 4 und Nr. 3, beide könnten in Funktion umgewandelt werden; # 2 mein Favorit - awk. Nr. 1 verwendet scriptBefehl - ein sehr vielseitiges Tool, das für die Aufzeichnung von Befehlszeilen im Allgemeinen nützlich ist. überall einsetzbar, für alles, was Sie aufnehmen möchten.

Ansatz Nr. 1: Es gibt einen /usr/bin/scriptBefehl (der standardmäßig mit ubuntu geliefert wird) für die Aufzeichnung der Befehlszeilenausgabe, der zusammen mit der Eingabeaufforderung und dem Befehl alles erfasst. Um nur einen Befehl und seine Ausgabe in einer bestimmten Datei zu speichern, verwenden Sie -cflag und geben Sie die Ausgabedatei an. Beispiel

xieerqi:$ script -c 'apt-cache depends gnome-terminal' outputFile.txt
Script started, file is outputFile.txt
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
     (extra output omitted)
Script done, file is outputFile.txt

xieerqi:$ cat outputFile.txt                                              
Script started on 20151022 星期四 085846
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  (extra output omitted)

Script done on 20151022 星期四 085846

Ansatz Nr. 2: awk hackery

Awk hat eine system()Funktion, mit der Sie Shell-Befehle über ein awkSkript oder einen Befehl ausführen können . Die Ausgabe wird auf dem Bildschirm angezeigt, Befehl zuerst, Ausgabe als nächstes. Um das, was Sie sehen, in eine Datei umzuleiten, verwenden Sie> Operator.

Dies kann auf zwei Arten erfolgen: Bitten Sie den Benutzer, Daten über stdin oder als Befehlszeilenargument einzugeben. Erstens ist es einfacher, dies zu erreichen, weshalb es veröffentlicht wird.

(1) awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'

 awk 'BEGIN{ print "Enter command to run: "; getline com < "/dev/stdin"; system(com) }'
Enter command to run: 
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0 
  (extra output omitted)

(2) Befehlszeilen-Args-Version; Ohne Ausgabe, um zu vermeiden, dass die Antwort zu lange dauert. Wieder anhängen >, um zur Datei umzuleiten

awk 'BEGIN{for (i=1; i<= ARGC; i++) myString = myString"  "ARGV[i]; print myString; system(myString)  }' apt-cache depends gnome-terminal

Ansatz 3: Bitten Sie bash, den Job für Sie zu erledigen

xieerqi@eagle:~$ bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND    '
apt-cache depends gnome-terminal
gnome-terminal
  Depends: gconf-service
    gconf-service:i386
  Depends: libatk1.0-0
  Depends: libc6
  Depends: libgconf-2-4
  Depends: libgdk-pixbuf2.0-0
  Depends: libglib2.0-0

Weiterleitung zur Datei mit >Operator:

bash -c ' MYCOMMAND="apt-cache depends gnome-terminal"; echo $MYCOMMAND ; $MYCOMMAND ' > output.txt

Ansatz 4: (mein zweiter Favorit)

Inspiriert von ByteCommanders Beitrag; Wir können readdie erforderlichen Befehle in der Subshell verwenden und dann ausführen

read command && (printf "COMMAND: %s" "$command";printf "\n+++++++\n"; sh -c "$command")

Probelauf:

xieerqi:$ read command && (printf "COMMAND READ: %s" "$command";printf "\n+++++++\nOUTPUT\n"; sh -c "$command")                                       
printf "This was a triumph; I'm making a note here - huge success"
COMMAND READ: printf "This was a triumph; I'm making a note here - huge success"
+++++++
OUTPUT
This was a triumph; I'm making a note here - huge success

Ansatz 5:

Verwenden Sie echooder here string(aka <<< "string"), um Argumente für sh -cthrough bereitzustellenxargs

xieerqi:$ echo "apt-cache policy gnome-terminal" | xargs -I {} bash -c 'echo {}; {}'                                                            
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

Und wenn Sie möchten, können Sie diesen Trick auch mit einem Alias ​​verwenden:

xieerqi:$ printAndRun <<< "apt-cache policy gnome-terminal"                                                                                     
apt-cache policy gnome-terminal
gnome-terminal:
  Installed: 3.6.2-0ubuntu1
  Candidate: 3.6.2-0ubuntu1
  Version table:
 *** 3.6.2-0ubuntu1 0
        500 http://us.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

xieerqi:$ type printAndRun
printAndRun is an alias for 'xargs -I {} bash -c "echo {}; {}"'
Sergiy Kolodyazhnyy
quelle
Schön, aber es enthält den Befehl nicht so wie Arronicals Code.
Gerechtigkeit für Monica
@DKBose Ich werde einen weiteren Ansatz hinzufügen, der den Befehl enthält. Fünf Minuten
Sergiy Kolodyazhnyy
@DKBose wie ist mein Ansatz # 2?
Sergiy Kolodyazhnyy
Das ist klug, ist awkwirklich ein sehr konfigurierbarer kleiner Kerl, nicht wahr? `script sieht auch für ein paar andere Zwecke praktisch aus.
Arronical
1
Dies ist die beste Antwort, da die Verwendung von Skripten alle Nebenwirkungen von Argumenten vermeidet, die möglicherweise Code ausführen, wenn sie mit Echo usw. angezeigt werden. Die zweite, beabsichtigte Ausführung führt möglicherweise zu anderen Ergebnissen als wenn der Befehl separat ausgeführt wird.
Joe
6
  1. Start script -q outputfile
  2. Führen Sie Ihren Befehl aus
  3. Presse Ctrl-D
  4. Öffne die Datei outputfile

Beispiel

Start script

[aboettger:~/tmp] % script -q ~/Desktop/kwin-depends

Starten Sie Ihren Befehl

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
[aboettger:~/tmp] % 

Presse Ctrl-D

Script done, file is /home/aboettger/Desktop/kwin-depends

Zeigen Sie Ihren Befehl und Ihre Ausgabe

[aboettger:~/tmp] % cat ~/Desktop/kwin-depends

und du wirst so etwas sehen

[aboettger:~/tmp] % apt-cache depends kde-window-manager
<kde-window-manager>
AB
quelle
5

Wenn Sie eine Alias-Erweiterung (nur Bash) wünschen, können Sie dies folgendermaßen tun:

function runcmd
{
    local check_cmd=${BASH_ALIASES[$1]}

    if [ -z "$check_cmd" ]; then
        check_cmd=$1
    fi

    shift #skip 1st arg

    echo "$check_cmd $@"
    $check_cmd $@
}

Du kannst jetzt rennen

runcmd acd leafpad > out
GARCIN David
quelle
4

Möglicherweise gibt es einen einfacheren Weg, aber Sie können dies mit einem Skript tun:

#!/bin/sh
echo $1
apt-cache depends $1

Erstellen Sie eine Datei scriptmit diesem Inhalt in Ihrem Basisordner und erteilen Sie die Ausführungsberechtigung

chmod +x script

Führen Sie es so aus:

./script kde-window-manager > ~/Desktop/kwin-depends
Pilot6
quelle
Dieser Ansatz hat den Vorteil, dass Sie diese Befehlszeile später einfach wiederholen können, wenn Sie möchten! Sie können die Umleitung auch in das Skript schreiben, so dass script.shimmer eine Datei erstellt wird, die script.logmit ihrer Ausgabe aufgerufen wird.
Gaurav
4

Extrem einfache Lösung mit einzeiliger Bash-Funktion

Vorbereitung:

Bei diesem Ansatz wird eine benutzerdefinierte Bash-Funktion verwendet, um die gewünschte Funktionalität bereitzustellen. Sie definieren es, indem Sie die folgende Zeile in Ihrer Terminalsitzung ausführen. Beachten Sie, dass Sie anstelle von runandlog: einen gültigen Namen für die Bash-Variable wählen können.

runandlog () ( IFS=' '; printf "[%s] $ %s\n%s\n" "$USER" "${*:2}" "$("${@:2}")" | tee -a "$1" | tail -n +2; )

Dies bleibt jedoch nur für die aktuelle Bash-Sitzung bestehen, dh nach dem Schließen des Terminalfensters ist die Funktion nicht mehr verfügbar.
Wenn Sie es dennoch versucht und gemocht haben, können Sie es jederzeit verfügbar machen, indem Sie Ihre ~/.bashrcDatei bearbeiten und diese Zeile an das Ende anhängen.

Wie benutzt man:

Nachdem Sie die Funktion definiert haben, können Sie sie zum Ausführen von Befehlen verwenden, während Sie den Befehl selbst und seine Ausgabe in einer Datei protokollieren. Sie können sogar weitere Informationen hinzufügen, z. B. den Benutzer, der sie ausgeführt hat, den ich bereits in die Funktion aufgenommen habe, oder die genaue Uhrzeit, zu der sie ausgeführt wurde. Feature-Wünsche in Kommentaren sind willkommen! :)

Die Syntax ist einfach:

runandlog LOGFILENAME YOUR-COMMAND-WITH-ARGUMENTS

Beispiel:

Eine Beispielsitzung als Benutzer bytecommander, die über das Basisverzeichnis ausgeführt wird, könnte folgendermaßen aussehen:

bytecommander: ~ $  runandlog mylogfile fortune
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos

Was dazu führt, dass im aktuellen Verzeichnis eine neue Datei mit folgendem Inhalt erstellt mylogfile wird (falls diese bereits vorhanden ist, hängt die Funktion die Ausgabe an!) :

[bytecommander] $ fortune 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos
Byte Commander
quelle
3

Ein ziemlich schlechter, aber funktionaler Trick wäre:

(echo "apt-cache depends kde-window-manager" && apt-cache depends kde-window-manager) > ~/Desktop/kwin-depends

Hässlich, aber es funktioniert!

Arronisch
quelle
Ich akzeptiere diese Antwort, weil die Lösung allgemeiner anwendbar ist.
Gerechtigkeit für Monica
@DKBose Sie müssen das Modul zweimal eingeben. Aber die Lösung mit einem Skript ist wirklich universell.
Pilot6
Es tut mir leid, dass ich diese Antwort nicht akzeptieren muss, obwohl sie das tut, wonach ich gefragt habe. Ich hoffe es macht dir nichts aus!
Gerechtigkeit für Monica
2
Kein Problem @DKBose, ich wusste, dass es eine ziemlich unelegante Lösung war, als ich die Antwort einreichte, und habe aus den veröffentlichten Alternativantworten einiges gelernt.
Arronical
2

Sie können den Befehl einfach an eine Funktion übergeben, die zuerst den Befehl und anschließend die Ausgabe des Befehls druckt. (Die Umleitungen werden absichtlich nicht in den gedruckten Befehl übernommen. Sie können dies leicht ändern, indem Sie die Anführungszeichen aus dem Befehl entfernen und $@stattdessen drucken und ausführen von $1in der Funktion):

function myfunction() {
    printf "%s\n\n" "$1"
    $1
}
$ myfunction "printf \"bar\n\"" > foo
$ cat foo
printf "bar\n"

bar

Um den Befehl später hinzuzufügen, können Sie diesen Befehl ausführen, der den zuletzt ausgeführten Befehl am Anfang einer Datei einfügt:

<<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
  • <<<"[...]": hier Zeichenfolge; [...]wird weitergeleitet zu cat's stdin;
  • $(<foo): Befehlsersetzung; Es wird durch den Inhalt von "foo" ersetzt.
  • cat [...] - >foo: verkettet stdinzu [...]und gibt zu "foo" aus;
  • <([...]): Prozessersetzung: wird durch einen Dateideskriptor ersetzt, der die Ausgabe von enthält [...];
  • history 2 | sed -n '1s/ [0-9][0-9]* \(.*\)/\1\n/p': gibt die letzten beiden Befehle aus, entfernt zwei Leerzeichen, gefolgt von einer oder mehreren Ziffern, gefolgt von zwei Leerzeichen in der ersten Zeile und druckt sie aus;
$ printf "bar\n" >foo
$ <<<"$(<foo)" cat <(history 2 | sed -n '1s/  [0-9][0-9]*  \(.*\)/\1\n/p') - >foo
$ cat foo
printf "bar" >foo

bar
kos
quelle
Warum drucken Sie nur $1? Und es gibt keine Notwendigkeit dafür eval.
Terdon
@terdon Nun, die Idee war, die Weiterleitungen aus dem gedruckten Befehl herauszuhalten, da ich dachte, dass dies in OPs Fall besser ausgesehen haben könnte. Trotzdem, wenn ich es jetzt ändere, wäre es identisch mit Ihrer Antwort. Allerdings ist ja evalnicht nötig, nicht sicher warum ich es vorher hinzugefügt habe. Vielen Dank.
Kos