Bagaimana saya bisa melihat baris perintah persis dieksekusi di dalam beberapa contoh bash?

29

Saya memiliki bashinstance berjalan lama (di dalam screensesi) yang mengeksekusi serangkaian perintah yang kompleks di dalam loop (dengan setiap loop melakukan pipa, pengalihan, dll).

Baris perintah panjang ditulis di dalam terminal - tidak ada di dalam skrip apa pun. Sekarang, saya tahu ID proses bash, dan saya memiliki akses root - bagaimana saya bisa melihat baris perintah yang tepat dieksekusi di dalamnya bash?

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

Dan dalam contoh shell lain, saya ingin melihat baris perintah dieksekusi di dalam PID 1234:

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'

Apakah ini mungkin?

EDIT # 1

Menambahkan contoh balasan untuk beberapa jawaban yang saya dapatkan.

  1. Tentang menggunakan di cmdlinebawah /proc/PID: itu tidak berhasil, setidaknya tidak dalam skenario saya. Berikut ini contoh sederhana:

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

    Di shell lain:

    $ cat /proc/8909/cmdline
    bash
  2. Menggunakan ps -p PID --noheaders -o cmdsama tidak berguna:

    $ ps -p 8909 --no-headers -o cmd
    bash
  3. ps -eaf juga tidak membantu:

    $ 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

    Artinya, tidak ada output dari baris perintah ORIGINAL, yang saya cari - yaitu while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done.

ttsiodras
sumber

Jawaban:

40

Saya tahu saya sedang berusaha, tetapi UNIX tidak pernah gagal!

Begini cara saya mengelolanya:

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

Kemudian pada (gdb)prompt saya menjalankan perintah, call write_history("/tmp/foo")yang akan menulis sejarah ini ke file /tmp/foo.

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

Saya kemudian lepas dari proses.

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

Dan berhenti gdb .

(gdb) q

Dan tentu saja ...

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

Agar mudah digunakan kembali di masa depan, saya menulis skrip bash , mengotomatiskan prosesnya.

ttsiodras
sumber
1
+1 sleuthing yang sangat bagus. Pastikan untuk menandai ini sebagai A yang dikecualikan dalam 2 hari.
slm
@slm: Terima kasih! Saya akan menulis posting blog tentang itu - itu menyenangkan, memburu ini.
ttsiodras
1
Dengan readline diaktifkan Anda juga dapat melakukan ini di gdb: print (char *)rl_line_buffer. Perintah saat ini secara berurutan adalah print (char *)the_printed_command. Anda mungkin juga call history_builtin(), tetapi itu akan menghasilkan pada tty dari proses bash, jadi mungkin kurang bermanfaat.
mr.spuratic
11
@slm: Tidak bisa menahan - Saya membuat blog tentang ini di sini: users.softlab.ece.ntua.gr/ ~ttsiod
bashheimer.html
1
Apakah bash thread-safe? Anda harus berharap Anda tidak mengubah beberapa kondisi internal yang mengganggu kode yang saat ini mengeksekusi ketika Anda mengeksekusi sesuatu dari gdb. Dalam praktiknya, bash hampir pasti hanya akan menunggu proses anaknya selesai setiap kali Anda menangguhkannya dengan gdb.
Adrian Pronk
5

Karena perintah masih berjalan di layar, bash induknya belum membaca ulang riwayat apa pun jadi:

  • pasang kembali ke layar
  • tekan ^Z laluup arrow
  • bonus: bungkus perintah dalam tanda kutip tunggal (menavigasi dengan ^A^A- karena layar (1) - dan^E ) dan gema + redirect ke file
  • fg untuk mengejar eksekusi perintah

Ada peringatan, tetapi ini cukup berguna, sebagian besar waktu.

Lloeki
sumber
Ya, bahkan membunuhnya dan mendesak up. Meskipun Anda harus yakin bahwa itu akan mulai lagi tanpa masalah, tetapi jika tidak maka Anda akan memiliki masalah yang sama setelah reboot. Anda hanya harus memilih saat ketika downtime tidak menjadi masalah.
Matthieu Napoli
0

Saya tahu Anda menemukan jawaban Anda sendiri, tetapi adakah alasan Anda tidak dapat melakukan hal seperti ini:

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

Mungkin Anda tidak dapat menggabungkan output dari pekerjaan aktual dan output dari bash yang menunjukkan baris yang sedang dijalankan.

Juga, FWIW, jika Anda lebih suka verbositas set -o xtrace,.

kuntul merah
sumber