Wie speichere ich den Terminalverlauf in einer Datei aus einer Bash-Datei?

7

Ich versuche, ein Bash-Skript zu erstellen, das den Terminalverlauf in einer Datei namens hist.txt speichert. Die Verwendung history > hist.txtscheint im Bash-Skript nicht zu funktionieren, funktioniert jedoch einwandfrei, wenn sie in der Befehlszeile ausgeführt wird.

Jede Anleitung wird sehr geschätzt.

Danke Judy

Judy
quelle
3
Ihre Frage ist etwas verwirrend. Was meinst du mit "scheint nicht in der Bash-Datei zu funktionieren, funktioniert aber gut, wenn es in der Kommandozeile ausgeführt wird"? Meinen Sie damit, dass Sie versuchen, Ihren Befehlsverlauf in einem ausgeführten Bash-Skript zu speichern? Wie in möchten Sie speichern, welche Befehle vom Skript ausgeführt wurden? Das Skript selbst ist in diesem Fall eine Geschichte.
Stephen
6
Oder möchten Sie den Bash-Verlauf eines bestimmten Benutzers ausgeben? Sie können einfach die ~/.bash_historyDatei des Benutzers lesen .
Arronical
1
@Arronical Hinweis, dass dies nur funktioniert, wenn der Benutzer Bash als Shell verwendet, was nicht immer der Fall ist.
1
@ p0llard Natürlich bin ich davon ausgegangen, dass es sich wie in einem Bash-Skript um Bash als Benutzer-Shell handelt, aber das ist möglicherweise nicht der Fall, wie Sie gesagt haben. Gutes Detail und Hintergrund in Ihrer Antwort Übrigens.
Arronical

Antworten:

11

Kurze Antwort

Führen Sie das Skript mit sourceoder aus .:

source ./script_name.sh

oder

. ./script_name.sh

Letzteres ist für verschiedene Schalen etwas kompatibler.

Lange Antwort

Diese Frage hebt einen wichtigen Punkt hervor, nämlich dass Shell-Skripte in ihrem eigenen Kontext ausgeführt werden. Betrachten Sie das folgende Shell-Skript, um zu sehen, was dies bedeutet:

#!/bin/bash

cd /
ls

Wenn Sie dies ausführen, erhalten Sie eine Ausgabe wie folgt:

bin  boot  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Sie werden jedoch feststellen, dass Sie sich nach dem Ausführen des Skripts immer noch in dem Verzeichnis befinden, in dem Sie sich vor dem Ausführen befanden: Das cd /Innere des Skripts hat Ihre Sitzung nicht wirklich beeinflusst - es hat nur den Kontext beeinflusst, in dem das Skript ausgeführt wurde, in welchem wird für die Ausführung des Skripts erstellt und bei seiner Rückkehr zerstört.

Der sourceBefehl liest 'Befehle aus dem Dateinamenargument im aktuellen Shell-Kontext und führt sie aus', sodass sich alle darin enthaltenen Befehle cdauf Ihre aktuelle Sitzung auswirken. Wenn Sie das obige Skript ausführen, indem Sie es an übergeben, werden sourceSie feststellen, dass Sie nach der Ausführung im Stammverzeichnis landen.

In diesem Fall besteht das Problem darin, dass der historyBefehl den Verlauf für den aktuellen Shell-Kontext angibt. Der Shell-Kontext, in dem Ihr Skript ohne Verwendung ausgeführt wird, sourcehat keinen Verlauf, sodass nichts in die Ausgabedatei geschrieben wird. Wenn Sie es verwenden source, wird es im richtigen Kontext ausgeführt und funktioniert wie erwartet.

NB: Ist sourceeine Shell eingebaut, kein Programm an sich - in Bash sourceist das gleichbedeutend mit ., aber in einigen Shells .funktioniert nur - habe ich sourcein dieser Antwort verwendet, weil es einfacher zu lesen ist als ., aber für maximale Kompatibilität .sollte verwendet werden.


quelle
Sehr interessante Lektüre. Ich habe mich immer über "fehlende" Verlaufsbefehle gewundert, jetzt weiß ich warum. Vielen Dank!
Tico
10

Beachten Sie zunächst, dass sich Ihr Verlauf bereits in einer Datei befindet. Wenn Sie Bash ausführen, lautet der Name normalerweise ~/.bash_history. Genauer gesagt ist es das, worauf Sie die Variable eingestellt haben HISTFILE. Wenn Sie es in eine andere Datei kopieren möchten, führen Sie es einfach auscat "$HISTFILE" > hist.txt

Der Grund, warum der historyBefehl in einem Bash-Shell-Skript nicht funktioniert, liegt daran, dass Skripte in einer nicht interaktiven untergeordneten Shell Ihrer aktuellen Shell-Sitzung ausgeführt werden. Untergeordnete Shells erben nicht die gesamte Umgebung des übergeordneten Elements (also nicht alle festgelegten Variablen), sondern nur die exportierten Variablen. Zur Veranschaulichung gibt das folgende Skript den Wert der Variablen wieder $var:

#!/bin/bash
echo "$var"

Stellen Sie $varnun etwas ein und führen Sie das Skript aus:

$ var="foo"
$ foo.sh
VAR: 

Als nächstes exportieren Sie zuerst die Variable:

$ var="foo"
$ export var
$ foo.sh
VAR: foo

Wie Sie sehen, steht die Variable nach dem Export für untergeordnete Shells zur Verfügung.

Wie bereits erwähnt, wird der Verlauf in der Datei gespeichert, auf die die Variable zeigt $HISTFILENAME. Da dies nicht standardmäßig exportiert wird, wird es beim Ausführen eines Skripts nicht festgelegt:

$ cat foo.sh
#!/bin/bash
echo "HISTFILE: $HISTFILE"
$ ./foo.sh
HISTFILE:
$ echo $HISTFILE
/home/terdon/.bash_history

Wie Sie im obigen Beispiel sehen können, wird die Variable HISTFILEin meiner normalen Shell-Sitzung festgelegt, ist jedoch beim Ausführen des Skripts leer.

Um den Verlauf zu erhalten, haben Sie einige Möglichkeiten:

  1. Der Standardwert HISTFILEist $HOME/.bash_history. Wenn Sie das nicht geändert haben, können Sie diesen Befehl einfach in Ihrem Skript ausführen:

    cat "$HOME/.bash_history" > history
  2. Sie können die $HISTFILEVariable an Ihr Skript übergeben und catdas:

    #!/bin/bash
    cat "$1" > history
    

    Speichern Sie das Obige als foo.shund führen Sie es wie folgt aus:

    ./foo.sh "$HISTORY"
  3. Stellen Sie sicher, dass die Variable exportiert wird. Fügen Sie diese Zeile zu Ihren ~/.bash_profile(falls vorhanden) oder ~/.profile(falls ~/.bash_profilenicht vorhanden) Dateien hinzu:

    export HISTFILE

    Melden Sie sich dann ab und wieder an, und Sie sollten in der Lage sein, history > hist.txtein Skript wie erwartet auszuführen . Dies liegt daran, export VARdass "$ VAR für Kinderschalen verfügbar machen" bedeutet. In der Praxis bedeutet dies, dass der Wert von HISTFILEvon der nicht interaktiven Shell geerbt wird, mit der Sie Ihr Skript ausführen.

    Während das festgelegt HISTFILEwird, wurde es von der Shell, die das Skript ausführt, nicht gelesen. Damit es funktioniert, müssen Sie es history -rzuerst lesen . Das ganze Skript würde so aussehen:

    $!/bin/bash
    history -r
    history > hist.txt
    

    Alternativ können Sie es auch manuell exportieren, bevor Sie das Skript ausführen:

    $ export HISTFILE

    Aber Sie müssen noch history -rim Skript.

  4. Sie können sourcees wie in der Antwort von @ p0llard vorgeschlagen .

Terdon
quelle