ps: perintah penuh terlalu panjang

26

Selamat siang!

Saya menggunakan 'ps' untuk melihat perintah yang memulai proses. Masalahnya adalah perintah itu terlalu panjang dan 'ps' tidak menunjukkannya sepenuhnya.

Contoh: Saya menggunakan perintah 'ps -p 2755 | less 'dan memiliki output berikut

  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.

Jadi, baris perintah terlalu panjang dan perintah berhenti di tengah kalimat. Bagaimana saya bisa melihatnya secara keseluruhan?

V. Artyukhov
sumber

Jawaban:

38

Di Linux, dengan psdari procps(-ng):

ps -fwwp 2755

Dalam versi Linux sebelum 4.2, masih terbatas (oleh kernel ( /proc/2755/cmdline) hingga 4k) dan Anda tidak bisa mendapatkan lebih banyak kecuali dengan meminta proses untuk memberitahukannya kepada Anda atau menggunakan debugger.

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

Untuk mencetak arg ke-4 hingga 5000 karakter:

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

Jika Anda menginginkan sesuatu yang tidak mengganggu, Anda bisa mencoba dan mendapatkan informasi dari /proc/2755/mem(perhatikan bahwa jika kernel.yama.ptrace_scopetidak diatur ke 0, Anda akan memerlukan izin pengguna super untuk itu). Ini di bawah ini berfungsi untuk saya (mencetak semua argumen dan variabel lingkungan), tetapi tidak ada banyak jaminan yang akan saya pikirkan (kesalahan dan penanganan input yang tidak terduga dibiarkan sebagai latihan untuk pembaca):

$ 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

(ganti "$!"dengan id proses). Di atas menggunakan fakta bahwa Linux menempatkan string menunjuk ke oleh argv[], envp[]dan nama file yang dieksekusi di bagian bawah tumpukan proses.

Di atas terlihat dalam tumpukan untuk string terbawah di antara dua set dua atau lebih byte NUL berturut-turut. Tidak berfungsi jika ada argumen atau string env kosong, karena Anda akan memiliki urutan 2 NUL byte di tengah argumen atau envp tersebut. Juga, kita tidak tahu di mana string argv berhenti dan di mana envp dimulai.

Pekerjaan di sekitar untuk itu adalah untuk memperbaiki heuristik itu dengan melihat ke belakang untuk konten aktual dari argv[](pointer). Ini di bawah ini berfungsi pada arsitektur i386 dan amd64 untuk executable ELF setidaknya:

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

Pada dasarnya, ia melakukan hal yang sama seperti di atas, tetapi begitu telah menemukan string pertama argv[](atau setidaknya satu argv[]atau envp[]string jika ada kosong), ia tahu alamatnya, sehingga terlihat mundur di bagian atas tumpukan untuk pointer dengan nilai yang sama. Kemudian terus melihat ke belakang hingga menemukan nomor yang tidak bisa menjadi penunjuk bagi mereka, dan itu argc. Maka bilangan bulat berikutnya adalah argv[0]. Dan mengetahui argv[0]dan argc, itu bisa menampilkan daftar argumen.

Itu tidak berfungsi jika proses telah menulis ke yang argv[]mungkin mengesampingkan beberapa pembatas NUL atau jika argc0 ( argcumumnya setidaknya 1 untuk dimasukkan argv[0]) tetapi harus bekerja dalam kasus umum setidaknya untuk executable ELF.

Di 4.2 dan yang lebih baru, /proc/<pid>/cmdlinetidak lagi terpotong, tetapi psitu sendiri memiliki lebar tampilan maksimum 128 ribu.

Stéphane Chazelas
sumber
Bisakah Anda memberi tahu lebih banyak tentang debugger? Bagaimana saya bisa melampirkannya ke proses yang sedang berjalan?
V. Artyukhov
1
@ V.Artyukhov Saya kira itulah yang -p $!dilakukannya ( $!adalah PID dari proses yang paling baru dimulai, yang karena latar belakangnya masih akan berjalan ketika gdb dipanggil).
CVn
Ya, melawan perintah yang panjang dengan perintah yang lebih panjang. Selain lelucon, +1 untuk jawabannya dengan penjelasan dan dokumentasi yang baik.
Stan Strum
12

Tambahkan satu atau dua -wbendera. Itu membuat output lebih luas. mis ps auxww.

Warren Young
sumber
5

Di Linux kernel 4.2 dan yang lebih baru, /proc/<pid>/cmdlinetidak lagi terpotong dan yang berikut ini berfungsi dengan baik:

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