Wie kann ich sehen, wie die genaue Befehlszeile in einer Bash-Instanz ausgeführt wird?

29

Ich habe eine lang laufende bashInstanz (innerhalb einer screenSitzung), die einen komplexen Satz von Befehlen innerhalb einer Schleife ausführt (wobei jede Schleife Pipes, Weiterleitungen usw. ausführt).

Die lange Befehlszeile wurde im Terminal geschrieben - sie befindet sich nicht in einem Skript. Jetzt kenne ich die Bash-Prozess-ID und habe Root-Zugriff. Wie kann ich sehen, wie genau die Befehlszeile darin ausgeführt wird bash?

Beispiel
bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

Und in einer anderen Shell-Instanz möchte ich die Befehlszeile sehen, die in PID 1234 ausgeführt wird:

bash$ echo $$
5678
bash$ su -
sh# cd /proc/1234
sh# # Do something here that will display the string  \
   'while true ; do someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done'

Ist das möglich?

EDIT # 1

Hinzufügen von Gegenbeispielen für einige Antworten, die ich habe.

  1. Über die Verwendung des cmdlineUnder /proc/PID: Das funktioniert nicht, zumindest nicht in meinem Szenario. Hier ist ein einfaches Beispiel:

    $ echo $$
    8909
    
    $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
    

    In einer anderen Shell:

    $ cat /proc/8909/cmdline
    bash
    
  2. Verwenden ps -p PID --noheaders -o cmdist genauso nutzlos:

    $ ps -p 8909 --no-headers -o cmd
    bash
    
  3. ps -eaf ist auch nicht hilfreich:

    $ ps -eaf | grep 8909
    ttsiod    8909  8905  0 10:09 pts/0    00:00:00 bash
    ttsiod   30697  8909  0 10:22 pts/0    00:00:00 sleep 30
    ttsiod   31292 13928  0 10:23 pts/12   00:00:00 grep --color=auto 8909
    

    Das heißt, es gibt keine Ausgabe der ORIGINAL - Befehlszeile, nach der ich suche - dh nach der while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done.

ttsiodras
quelle

Antworten:

40

Ich wusste, dass ich nach Strohhalmen griff, aber UNIX scheitert nie!

So habe ich es geschafft:

bash$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()

Dann habe (gdb)ich an der Eingabeaufforderung den Befehl ausgeführt, call write_history("/tmp/foo")der diesen Verlauf in die Datei schreibt /tmp/foo.

(gdb) call write_history("/tmp/foo")
$1 = 0

Ich trenne mich dann vom Prozess.

(gdb) detach
Detaching from program: /bin/bash, process 8909

Und hör auf gdb.

(gdb) q

Und sicher genug ...

bash$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

Für eine einfache spätere Wiederverwendung habe ich ein Bash-Skript geschrieben , das den Prozess automatisiert.

ttsiodras
quelle
1
+1 sehr schönes Sleuthing.Bezeichnen Sie dies in 2 Tagen als das ausgenommene A.
slm
@slm: Danke! Ich werde einen Blog-Beitrag darüber schreiben - es hat Spaß gemacht, das aufzuspüren.
Ttsiodras
1
Mit Readline- aktiviert können Sie dies auch in gdb: print (char *)rl_line_buffer. Der aktuelle Befehl in einer Sequenz lautet print (char *)the_printed_command. Sie können auch call history_builtin(), aber das wird auf die tty des Bash-Prozesses ausgegeben, so dass es möglicherweise weniger nützlich ist.
mr.spuratic
11
@slm: Konnte nicht widerstehen - ich habe hier darüber gebloggt
ttsiodras
1
Ist bash threadsicher? Sie müssen hoffen, dass Sie keinen internen Status ändern, der den aktuell ausgeführten Code stört, wenn Sie etwas von gdb ausführen. In der Praxis wartet bash mit ziemlicher Sicherheit nur darauf, dass der untergeordnete Prozess beendet wird, wenn Sie ihn mit gdb aussetzen.
Adrian Pronk
5

Da der Befehl immer noch auf dem Bildschirm ausgeführt wird, hat die übergeordnete Bash keinen Verlauf erneut gelesen.

  • Schließen Sie den Bildschirm erneut an
  • drücken Sie ^Zdannup arrow
  • Bonus: wickeln Sie den Befehl in einfachen Anführungszeichen (Navigation mit ^A^A- weil Bildschirm (1) - und ^E) und Echo + Umleitung in eine Datei
  • fg Befehlsausführung zu verfolgen

Es gibt Vorbehalte, aber dies ist die meiste Zeit nützlich genug.

Lloeki
quelle
Ja, sogar töten und drücken up. Sie müssen sich zwar sicher sein, dass es ohne Probleme wieder gestartet wird, aber wenn dies nicht der Fall ist, haben Sie nach einem Neustart trotzdem das gleiche Problem. Sie müssen nur den Moment auswählen, in dem Ausfallzeiten kein Problem darstellen.
Matthieu Napoli
0

Ich weiß, dass Sie Ihre eigene Antwort gefunden haben, aber gibt es einen Grund, warum Sie so etwas nicht tun können:

(set -x; for f in 1 2 3 4 ; do  echo "$f"; sleep $f; done)

Möglicherweise können Sie die Ausgabe des aktuellen Jobs und die Ausgabe der Bash, die die aktuell ausgeführte Zeile zeigt, nicht miteinander mischen.

Auch FWIW, wenn Sie es vorziehen Ausführlichkeit set -o xtrace.

Purpurreiher
quelle