ps: full command ist zu lang

26

Schönen Tag!

Ich benutze 'ps', um den Befehl zu sehen, der den Prozess startet. Das Problem ist, dass der Befehl zu lang ist und 'ps' ihn nicht vollständig anzeigt.

Beispiel: Ich verwende den Befehl 'ps -p 2755 | weniger 'und haben folgende Ausgabe

  PID TTY      STAT   TIME COMMAND
2755 ?        Sl   305:05 /usr/java/jdk1.6.0_37/bin/java -Xms64m -Xmx512m -Dflume.monitoring.type=GANGLIA -Dflume.monitoring.hosts=prod.hostname.ru:8649 -cp /etc/flume-ng/conf/acrs-event:/usr/lib/flume-ng/lib/*:/etc/hadoop/conf:/usr/lib/hadoop/lib/activation-1.1.jar:/usr/lib/hadoop/lib/asm-3.2.jar:/usr/lib/hadoop/lib/avro-1.7.4.jar:/usr/lib/hadoop/lib/commons-beanutils-1.7.0.jar:/usr/lib/hadoop/lib/commons-beanutils-core-1.8.0.jar:/usr/lib/hadoop/lib/commons-cli-1.2.jar:/usr/lib/hadoop/lib/commons-codec-1.4.jar:/usr/lib/hadoop/lib/commons-collections-3.2.1.jar:/usr/lib/hadoop/lib/commons-compress-1.4.1.jar:/usr/lib/hadoop/lib/commons-configuration-1.6.jar:/usr/lib/hadoop/lib/commons-digester-1.8.jar:/usr/lib/hadoop/lib/commons-el-1.0.jar:/usr/lib/hadoop/lib/commons-httpclient-3.1.jar:/usr/lib/hadoop/lib/commons-io-2.1.jar:/usr/lib/hadoop/lib/commons-lang-2.5.jar:/usr/lib/hadoop/lib/commons-logging-1.1.1.jar:/usr/lib/hadoop/lib/commons-math-2.1.jar:/usr/lib/hadoop/lib/commons-net-3.1.jar:/usr/lib/hadoop/lib/guava-11.0.2.jar:/usr/lib/hadoop/lib/jackson-core-asl-1.8.8.jar:/usr/lib/hadoop/lib/jackson-jaxrs-1.8.8.jar:/usr/lib/hadoop/lib/jackson-mapper-asl-1.8.8.jar:/usr/lib/hadoop/lib/jackson-xc-1.8.8.jar:/usr/lib/hadoop/lib/jasper-compiler-5.5.23.jar:/usr/lib/hadoop/lib/jasper-runtime-5.5.23.jar:/usr/lib/hadoop/lib/jaxb-api-2.2.2.jar:/usr/lib/hadoop/lib/jaxb-impl-2.2.3-1.jar:/usr/lib/hadoop/lib/jersey-core-1.8.jar:/usr/lib/hadoop/lib/jersey-json-1.8.jar:/usr/lib/hadoop/lib/jersey-server-1.8.jar:/usr/lib/hadoop/lib/jets3t-0.6.1.jar:/usr/lib/hadoop/lib/jettison-1.1.jar:/usr/lib/hadoop/lib/jetty-6.1.26.cloudera.2.jar:/usr/lib/hadoop/lib/jetty-util-6.1.26.cloudera.2.jar:/usr/lib/hadoop/lib/jline-0.9.94.jar:/usr/lib/hadoop/lib/jsch-0.1.42.jar:/usr/lib/hadoop/lib/jsp-api-2.1.jar:/usr/lib/hadoop/lib/jsr305-1.3.9.jar:/usr/lib/hadoop/lib/junit-4.8.2.jar:/usr/lib/hadoop/lib/kfs-0.3.jar:/usr/lib/hadoop/lib/log4j-1.2.17.jar:/usr/lib/hadoop/lib/mockito-all-1.8.5.jar:/usr/lib/hadoop/lib/native:/usr/lib/hadoop/lib/paranamer-2.3.jar:/usr/lib/hadoop/lib/protobuf-java-2.4.0a.jar:/usr/lib/hadoop/lib/servlet-api-2.5.jar:/usr/lib/hadoop/lib/snappy-java-1.0.4.1.jar:/usr/lib/hadoop/lib/stax-api-1.0.1.jar:/usr/lib/hadoop/lib/xmlenc-0.52.jar:/usr/lib/hadoop/lib/xz-1.0.jar:/usr/lib/hadoop/lib/zookeeper-3.4.5-cdh4.3.0.jar:/usr/lib/hadoop/.//bin:/usr/lib/hadoop/.//cloudera:/usr/lib/hadoop/.//etc:/usr/lib/hadoop/.//hadoop-annotations-2.0.0-cdh4.3.0.jar:/usr/lib/hadoop/.//hadoop-annotations.jar:/usr/lib/hadoop/.//hadoop-auth-2.0.0-cdh4.3.0.jar:/usr/lib/hadoop/.//hadoop-auth.jar:/usr/lib/hadoop/.//hadoop-common-2.0.0-cdh4.3.0.jar:/usr/lib/hadoop/.//hadoop-common-2.0.0-cdh4.3.0-tests.jar:/usr/lib/hadoop/.//hadoop-common.jar:/usr/lib/hadoop/.//lib:/usr/lib/hadoop/.//libexec:/usr/lib/hadoop/.//sbin:/usr/lib/hadoop-hdfs/./:/usr/lib/hadoop-hdfs/lib/asm-3.2.jar:/usr/lib/hadoop-hdfs/lib/commons-cli-1.2.jar:/usr/lib/hadoop-hdfs/lib/commons-codec-1.4.jar:/usr/lib/hadoop-hdfs/lib/commons-daemon-1.0.3.jar:/usr/lib/hadoop-hdfs/lib/commons-el-1.0.jar:/usr/lib/hadoop-hdfs/lib/commons-io-2.1.jar:/usr/lib/hadoop-hdfs/lib/commons-lang-2.5.jar:/usr/lib/hadoop-hdfs/lib/commons-logging-1.1.1.jar:/usr/lib/hadoop-hdfs/lib/guava-11.0.2.jar:/usr/lib/hadoop-hdfs/lib/jackson-core-asl-1.8.8.jar:/usr/lib/hadoop-hdfs/lib/jackson-mapper-asl-1.8.8.jar:/usr/lib/hadoop-hdfs/lib/jasper-runtime-5.5.23.jar:/usr/lib/hadoop-hdfs/lib/jersey-core-1.8.jar:/usr/lib/hadoop-hdfs/lib/jersey-server-1.8.jar:/usr/lib/hadoop-hdfs/lib/jetty-6.1.26.cloudera.2.jar:/usr/lib/hadoop-hdfs/lib/jetty-util-6.1.26.cloudera.2.jar:/usr/lib/hadoop-hdfs/lib/jline-0.9.94.jar:/usr/lib/hadoop-hdfs/lib/jsp-api-2.1.jar:/usr/lib/hadoop-hdfs/lib/jsr305-1.3.9.jar:/usr/lib/hadoop-hdfs/lib/log4j-1.2.17.jar:/usr/lib/hadoop-hdfs/lib/protobuf-java-2.4.0a.jar:/usr/lib/hadoop-hdfs/lib/servlet-api-2.5.jar:/usr/lib/hadoop-hdfs/lib/xmlenc-0.52.jar:/usr/lib/hadoop-hdfs/lib/zookeeper-3.4.5-cdh4.3.0.jar:/usr/lib/hadoop-hdfs/.//bin:/usr/lib/hadoop-hdfs/.//cloudera:/usr/lib/hadoop-hdfs/.//hadoop-hdfs-2.0.0-cdh4.3.0.jar:/usr/lib/hadoop-hdfs/.//hadoop-hdfs-2.0.

Die Befehlszeile ist also zu lang und der Befehl stoppt mitten in der Phrase. Wie kann ich das Ganze sehen?

V. Artyukhov
quelle

Antworten:

38

Unter Linux mit dem psvon procps(-ng):

ps -fwwp 2755

In Linux-Versionen vor 4.2 ist es jedoch immer noch begrenzt (vom Kernel ( /proc/2755/cmdline) auf 4k) und Sie können nicht mehr erhalten, außer indem Sie den Prozess bitten, es Ihnen mitzuteilen oder einen Debugger zu verwenden.

$ sh -c 'sleep 1000' $(seq 4000) &
[1] 31149
$ gdb -p $! /bin/sh
[...]
Attaching to program: /bin/dash, process 31149
[...]
(gdb) bt
#0  0x00007f40d11f40aa in wait4 () at ../sysdeps/unix/syscall-template.S:81
[...]
#7  0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
#8  0x00000000004024a5 in ?? ()
#9  0x00007fff5b9f5a78 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb) frame 7
#7  0x00007f40d115c995 in __libc_start_main (main=0x4022c0, argc=4003, ubp_av=0x7fff5b9f5a88, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff5b9f5a78)
at libc-start.c:260
(gdb) x/4003s *ubp_av
0x7fff5b9ff83e: "sh"
0x7fff5b9ff841: "-c"
0x7fff5b9ff844: "sleep 1000"
0x7fff5b9ff84f: "1"
0x7fff5b9ff851: "2"
[...]
0x7fff5ba04212: "3999"
0x7fff5ba04217: "4000"

So drucken Sie das 4. Argument mit bis zu 5000 Zeichen:

(gdb) set print elements 5000
(gdb) p ubp_av[3]

Wenn Sie etwas möchten, das nicht aufdringlich ist, können Sie versuchen, die Informationen von /proc/2755/memabzurufen (beachten Sie, dass kernel.yama.ptrace_scopeSie Superuser-Berechtigungen dafür benötigen , wenn der Wert nicht auf 0 festgelegt ist). Das Folgende funktioniert für mich (druckt alle Argumente und Umgebungsvariablen aus), aber ich denke, es gibt nicht viel Garantie (der Fehler und die unerwartete Eingabe werden dem Leser als Übung überlassen):

$ perl -e '$p=shift;open MAPS, "/proc/$p/maps";
          ($m)=grep /\[stack\]/, <MAPS>;
          ($a,$b)=map hex, $m =~ /[\da-f]+/g;
          open MEM, "/proc/$p/mem" or die "open mem: $!";
          seek MEM,$a,0; read MEM, $c,$b-$a;
          print((split /\0{2,}/,$c)[-1])' "$!" | tr \\0 \\n | head
sh
-c
sleep 1000
1
2
3
4
5
6
7

(durch "$!"die Prozess-ID ersetzen ). Das Obige nutzt die Tatsache, dass Linux die Zeichenfolgen, auf die durch gezeigt wird argv[], envp[]und den ausgeführten Dateinamen am Ende des Stapels des Prozesses platziert.

Das Obige sucht in diesem Stapel nach der untersten Zeichenfolge zwischen zwei Sätzen von zwei oder mehr aufeinanderfolgenden NUL-Bytes. Es funktioniert nicht, wenn eines der Argumente oder env-Zeichenfolgen leer ist, da Sie dann eine Folge von 2 NUL-Bytes in der Mitte dieser argv- oder envp-Zeichenfolgen haben. Außerdem wissen wir nicht, wo die argv-Zeichenfolgen aufhören und wo die envp-Zeichenfolgen beginnen.

Eine Lösung dafür wäre, diese Heuristik zu verfeinern, indem Sie rückwärts nach dem tatsächlichen Inhalt von argv[](den Zeigern) suchen . Das Folgende funktioniert auf i386- und amd64-Architekturen für ELF-ausführbare Dateien mindestens:

perl -le '$p=shift;open MAPS, "/proc/$p/maps";
      ($m)=grep /\[stack\]/, <MAPS>;
      ($a,$b)=map hex, $m =~ /[\da-f]+/g;
      open MEM, "/proc/$p/mem" or die "open mem: $!";
      seek MEM,$a,0; read MEM, $c,$b-$a;
      $c =~ /.*\0\0\K[^\0].*\0[^\0]*$/s;
      @a=unpack"L!*",substr$c,0,$-[0];
      for ($i = $#a; $i >=0 && $a[$i] != $a+$-[0];$i--) {}
      for ($i--; $i >= 0 && ($a[$i]>$a || $a[$i]==0); $i--) {}
      $argc=$a[$i++];
      print for unpack"(Z*)$argc",substr$c,$a[$i]-$a;' "$!"

Grundsätzlich tut es die gleiche wie oben, aber sobald sie die erste Folge von gefunden haben argv[](oder zumindest eine der argv[]oder envp[]Strings , wenn es Leergut), es kennt seine Adresse, so dass es in dem oberen Rest des Stapels nach hinten sucht ein Zeiger mit dem gleichen Wert. Schauen Sie dann so lange zurück, bis eine Zahl gefunden wird, die nicht mehr als Hinweis auf diese Zahlen dienen kann argc. Dann ist die nächste ganze Zahl argv[0]. Wenn Sie argv[0]und kennen argc, kann die Liste der Argumente angezeigt werden.

Das funktioniert nicht, wenn der Prozess in seine argv[]möglicherweise überschreibenden NUL-Begrenzer geschrieben hat oder wenn argc0 ist (sollte argcim Allgemeinen mindestens 1 enthalten sein argv[0]), sollte aber im Allgemeinen zumindest für ELF-ausführbare Dateien funktionieren.

In 4.2 und neuer /proc/<pid>/cmdlinewird nicht mehr abgeschnitten, sondern hat psselbst eine maximale Anzeigebreite von 128K.

Stéphane Chazelas
quelle
Könnten Sie bitte mehr über den Debugger erzählen? Wie kann ich es an den laufenden Prozess anhängen?
V. Artyukhov
1
@V.Artyukhov Ich nehme an, das ist, was das -p $!tut ( $!ist die PID des zuletzt gestarteten Prozesses, der, da er im Hintergrund läuft, immer noch läuft, wenn gdb aufgerufen wird).
ein Lebenslauf vom
Ja, kämpfe mit langen Befehlen mit noch längeren Befehlen. Scherze beiseite, +1 für die Antwort mit einer guten Erklärung und Dokumentation.
Stan Strum
12

Fügen Sie ein oder zwei -wFlags hinzu. Dadurch wird die Ausgabe breiter. zB ps auxww.

Warren Young
quelle
5

In Linux-Kernel 4.2 und neuer /proc/<pid>/cmdlineist nicht mehr abgeschnitten und das folgende funktioniert gut:

xargs -0 printf '%s\n' < /proc/2755/cmdline
Tim Lewis
quelle