ฉันจะดูบรรทัดคำสั่งที่แน่นอนถูกเรียกใช้งานในอินสแตนซ์ของ bash ได้อย่างไร


29

ฉันมีbashอินสแตนซ์ที่ใช้เวลานาน(ภายในscreenเซสชัน) ที่กำลังดำเนินการชุดคำสั่งที่ซับซ้อนภายในลูป

บรรทัดคำสั่งยาวเขียนอยู่ในเทอร์มินัล - มันไม่ได้อยู่ในสคริปต์ใด ๆ ตอนนี้ฉันรู้รหัสกระบวนการทุบตีและฉันมีการเข้าถึงรูท - ฉันจะดูบรรทัดคำสั่งที่ถูกดำเนินการภายในได้bashอย่างไร

ตัวอย่าง
bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

และในอินสแตนซ์ของเชลล์อื่นฉันต้องการดูบรรทัดคำสั่งที่ดำเนินการภายใน 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'

เป็นไปได้ไหม

แก้ไข # 1

การเพิ่มตัวอย่างตอบโต้สำหรับคำตอบบางอย่างที่ฉันมี

  1. เกี่ยวกับการใช้อันcmdlineใต้/proc/PID: นั่นใช้งานไม่ได้อย่างน้อยก็ไม่ได้อยู่ในสถานการณ์ของฉัน นี่คือตัวอย่างง่ายๆ:

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

    ในเปลือกอื่น:

    $ cat /proc/8909/cmdline
    bash
  2. การใช้ps -p PID --noheaders -o cmdนั้นไร้ประโยชน์เช่นเดียวกับ:

    $ ps -p 8909 --no-headers -o cmd
    bash
  3. ps -eaf ยังไม่เป็นประโยชน์:

    $ 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

    นั่นคือมีการส่งออกของบรรทัดคำสั่งเดิมซึ่งเป็นสิ่งที่ผมกำลังมองหาไม่ - while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; doneคือ

คำตอบ:


40

ฉันรู้ว่ากำลังจับฟาง แต่ UNIX ไม่เคยล้มเหลว!

นี่คือวิธีที่ฉันจัดการ:

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

แล้วที่(gdb)ฉันพรอมต์วิ่งคำสั่งที่จะเขียนประวัติศาสตร์นี้ไปยังแฟ้มcall write_history("/tmp/foo")/tmp/foo

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

ฉันแยกออกจากกระบวนการ

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

gdbและเลิก

(gdb) q

และนั่นเอง ...

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

เพื่อการใช้งานในอนาคตได้อย่างง่ายดายฉันเขียนสคริปต์ทุบตีโดยอัตโนมัติกระบวนการ


1
+1 นักสืบที่ดีมากอย่าลืมทำเครื่องหมายว่า A ยกเว้นใน 2 วัน
slm

@slm: ขอบคุณ! ฉันจะเขียนโพสต์บล็อกเกี่ยวกับมัน - มันสนุกนะการล่าสัตว์นี้
ttsiodras

1
ด้วยReadLineเปิดใช้งานคุณยังสามารถทำเช่นนี้ใน:gdb คำสั่งปัจจุบันในลำดับคือprint (char *)rl_line_buffer print (char *)the_printed_commandคุณอาจจะทำเช่นcall history_builtin()นั้น แต่มันจะออกมาใน tty ของกระบวนการ bash ดังนั้นมันอาจมีประโยชน์น้อยกว่า
mr.spuratic

11
@slm: ไม่สามารถต้านทาน - ฉัน blogged เกี่ยวกับที่นี่: users.softlab.ece.ntua.gr/~ttsiod/bashheimer.html
ttsiodras

1
bash thread-safe หรือไม่ คุณจะต้องหวังว่าคุณจะไม่แก้ไขสถานะภายในบางอย่างที่ทำให้โค้ดที่กำลังเรียกใช้งานผิดเมื่อคุณรันบางอย่างจาก gdb ในทางปฏิบัติการทุบตีจะแทบรอให้กระบวนการลูกเสร็จสิ้นเมื่อใดก็ตามที่คุณระงับ gdb
Adrian Pronk

5

เนื่องจากคำสั่งยังคงทำงานอยู่ในหน้าจอการทุบตีหลักของมันจึงไม่อ่านประวัติซ้ำดังนั้น:

  • แนบหน้าจออีกครั้ง
  • กด^Zแล้วup arrow
  • โบนัส: ห่อคำสั่งด้วยเครื่องหมายคำพูดเดี่ยว (การนำทางด้วย^A^A- เพราะหน้าจอ (1) - และ^E) และ echo + เปลี่ยนเส้นทางไปยังไฟล์
  • fg เพื่อติดตามการดำเนินการคำสั่ง

มีข้อแม้ แต่นี่มีประโยชน์มากที่สุด


upใช่แม้ฆ่ามันและกด แม้ว่าคุณจะต้องมั่นใจว่ามันจะเริ่มต้นอีกครั้งโดยไม่มีปัญหาใด ๆ แต่ถ้าไม่เช่นนั้นคุณจะมีปัญหาเดียวกันหลังจากรีบูตอย่างไรก็ตาม คุณเพียงแค่ต้องเลือกช่วงเวลาของคุณเมื่อการหยุดทำงานไม่เป็นปัญหา
Matthieu Napoli

0

ฉันรู้ว่าคุณพบคำตอบของคุณเอง แต่มีเหตุผลที่คุณไม่สามารถทำสิ่งนี้:

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

บางทีคุณไม่สามารถรวมเอาท์พุทของงานจริงและเอาท์พุทจากการทุบตีแสดงสายการดำเนินการในปัจจุบัน

นอกจากนี้ FWIW หากคุณต้องการใช้คำฟุ่มเฟื่อย, set -o xtrace.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.