ps: pełne polecenie jest za długie

26

Dobry dzień!

Używam „ps”, aby zobaczyć polecenie, które uruchamia proces. Problem polega na tym, że polecenie jest za długie i „ps” nie pokazuje go całkowicie.

Przykład: używam polecenia „ps -p 2755 | mniej ”i mają następujące dane wyjściowe

  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.

Tak więc linia poleceń jest za długa, a polecenie zatrzymuje się w połowie frazy. Jak mogę zobaczyć to w całości?

V. Artyukhov
źródło

Odpowiedzi:

38

W systemie Linux psz procps(-ng):

ps -fwwp 2755

W wersjach Linuksa wcześniejszych niż 4.2 jest jednak nadal ograniczony (przez jądro ( /proc/2755/cmdline) do 4k) i nie można uzyskać więcej, niż prosząc proces, aby ci to powiedział lub skorzystał z debuggera.

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

Aby wydrukować 4. argument z maksymalnie 5000 znaków:

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

Jeśli chcesz czegoś nieinwazyjnego, możesz spróbować uzyskać informacje od /proc/2755/mem(pamiętaj, że jeśli kernel.yama.ptrace_scopenie jest ustawiony na 0, będziesz potrzebował do tego uprawnień administratora). To poniżej działa dla mnie (wypisuje wszystkie argumenty i zmienne środowiskowe), ale nie ma wiele gwarancji, że bym pomyślał (błąd i nieoczekiwana obsługa danych wejściowych pozostała jako ćwiczenie dla czytelnika):

$ 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

(zamień "$!"na identyfikator procesu). Powyższe wykorzystuje fakt, że Linux umieszcza ciągi wskazane przez argv[], envp[]a wykonaną nazwę pliku na dole stosu procesu.

Powyżej wygląda na tym stosie łańcuch znajdujący się na najniższym końcu między dwoma zestawami dwóch lub więcej kolejnych NUL bajtów. Nie działa, jeśli którykolwiek z argumentów lub ciągów env jest pusty, ponieważ wtedy będziesz miał sekwencję 2 NUL bajtów pośrodku tych argumentów lub envp. Nie wiemy też, gdzie kończą się ciągi argumentów i gdzie zaczynają się te envp.

Rozwiązaniem tego problemu byłoby udoskonalenie tej heurystyki poprzez spojrzenie wstecz na rzeczywistą treść argv[](wskaźników). To poniżej działa na architekturze i386 i amd64 co najmniej dla plików wykonywalnych ELF:

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;' "$!"

Zasadniczo robi to samo, co powyżej, ale po znalezieniu pierwszego ciągu argv[](lub co najmniej jednego z ciągów argv[]lub, envp[]jeśli istnieją opróżnienia), zna swój adres, więc szuka wstecz w górnej części stosu wskaźnik o tej samej wartości. Następnie patrzy wstecz, aż znajdzie liczbę, która nie może być wskaźnikiem do nich, i to jest argc. Następna liczba całkowita to argv[0]. I wiedząc, argv[0]i argcmoże wyświetlić listę argumentów.

To nie działa, jeśli proces zapisał, że argv[]może przesłonić niektóre ograniczniki NUL lub jeśli argcwynosi 0 ( argczwykle jest to co najmniej 1, aby je uwzględnić argv[0]), ale powinien działać w ogólnym przypadku przynajmniej dla plików wykonywalnych ELF.

W wersji 4.2 i nowszej /proc/<pid>/cmdlinenie jest już obcinany, ale pssam ma maksymalną szerokość wyświetlania 128K.

Stéphane Chazelas
źródło
Czy możesz powiedzieć coś więcej o debuggerze? Jak mogę dołączyć go do uruchomionego procesu?
V. Artyukhov,
1
@ V.Artyukhov Zakładam, że tak właśnie -p $!działa ( $!jest to PID ostatnio rozpoczętego procesu, który ponieważ jest w tle, będzie nadal działał po wywołaniu gdb).
CVn
Tak, walcz z długimi poleceniami jeszcze dłuższymi. Żarty na bok, +1 za odpowiedź z dobrym wyjaśnieniem i dokumentacją.
Stan Strum,
12

Dodaj jedną lub dwie -wflagi. To sprawia, że ​​wyjście jest szersze. np ps auxww.

Warren Young
źródło
5

W jądrze Linuksa 4.2 i nowszych /proc/<pid>/cmdlinenie jest już obcinany, a następujące działania działają ładnie:

xargs -0 printf '%s\n' < /proc/2755/cmdline
Tim Lewis
źródło