เปลี่ยนเส้นทาง stderr จากสคริปต์ที่รันอยู่แล้ว


14

ฉันใช้สคริปต์มาหลายวันแล้ว ฉันเปลี่ยนเส้นทาง stdout ไป$HOME/mylogแล้ว แต่ไม่เปลี่ยนเส้นทาง stderr เนื่องจากฉันคิดว่าจะไม่มีอะไรเกิดขึ้น ทันใดนั้นหลายพันบรรทัดก็เริ่มปรากฏบน stderr ดังนั้นฉันจึงหยุดงานชั่วคราว มีวิธีที่ฉันสามารถเปลี่ยนเส้นทาง stderr $HOME/myerrจากนี้ไปโดยไม่ต้องรีสตาร์ทสคริปต์หรือไม่

ฉันเข้าถึง sudo บนกล่องได้และเป็น OS X

บางทีมีบางอย่างที่ใช้ dtools trapping?

ฉันไม่สามารถทำงานที่สคริปต์ทำหายไปและเริ่มต้นใหม่ตั้งแต่ต้น มีวิธีการ "ถ่ายโอนข้อมูลวัตถุในหน่วยความจำ" บนดิสก์ตรึงโปรแกรมแก้ไขตัวแปร (เช่นตัวอธิบายไฟล์) และดำเนินการต่อด้วยบริบทใหม่หรือไม่


คำตอบ:


12

ฉันคิดว่าเป็นไปได้ถ้าคุณแนบกระบวนการของล่ามที่เกี่ยวข้องกับ gdb ฉันลองด้วย perl one-liner

 perl -e 'do { print "x\n"; sleep(1) } while(1)'

และใช้งานได้ แต่น่าเสียดายที่ไม่มีสคริปต์ทุบตีคล้าย


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

attach PID
call close(2)
call open("/abs/olu/te/path/filename", 65, 384)
detach PID

หลังจากนั้นข้อมูลทั้งหมดที่ถูกเขียนไปยังจะstderrถูกเปลี่ยนเส้นทางไป/abs/olu/te/path/filenameตั้งแต่

  • attach PID แนบกระบวนการกับ gdb และหยุดมัน
  • call close(2)ปิดstderrfilescriptor ของกระบวนการ (สำหรับstdoutfilescriptor คือ 1)
  • call open(...) เปิดไฟล์ใหม่และรับจำนวนเต็มที่ไม่ได้ใช้ต่ำสุดสำหรับไฟล์ที่สร้างขึ้นใหม่และ
  • detach PID ดำเนินการต่อกระบวนการ

อย่างน้อยในเครื่องของฉัน สองบรรทัดแรกเข้ากันได้กับ POSIX แต่ไม่ใช่บรรทัดที่สาม

อาร์กิวเมนต์ที่สองและอาร์กิวเมนต์ที่สามของopenในบรรทัดที่สามมีการบันทึกman 2 openไว้ ในกรณีของฉัน 65 หมายความว่าopenควรสร้างไฟล์และเปิดไฟล์แบบเขียนอย่างเดียวO_WRONLY | O_CREAT(กำหนดไว้ในfcntl.h) อาร์กิวเมนต์ที่สามบอกให้เปิดเพื่อสร้างไฟล์ที่มีสิทธิ์ในการอ่านและเขียนสำหรับผู้ใช้เช่นS_IWUSR | S_IRUSR(กำหนดไว้ในsys/stat.h) ดังนั้นคุณอาจต้องค้นหาค่าที่เหมาะสมในเครื่องของคุณด้วยตัวเอง


มันใช้งานได้ดีมาก ...
Robottinosino

8

นี่คือคำตอบที่หยาบคายและฉันหวังว่าคนอื่นจะทำได้ดีกว่า แต่ถ้าไม่มีแนวคิดอื่น ๆ ให้แนบ gdb และบังคับให้กระบวนการสร้าง syscalls สองสามอัน:

(gdb) attach 12345 # target PID
(gdb) p close(2)
(gdb) p open("errfile", O_WRONLY)
(gdb) c

ดี ฉันไม่รู้ว่า gdb สามารถทำเช่นนั้นได้ มีวิธีการบังคับให้หมายเลขไฟล์อธิบายเฉพาะหรือไม่ เช่นบอกว่าถ้า FD 1 ไม่ได้ใช้และopen()คว้า FD 1 หรือไม่ หรือคุณแค่ต้องโทรหาdup()สองสามครั้ง?
แพทริค

ไม่p open("errfile", O_WRONLY)จริงๆทำงานบนเครื่องของคุณ?
user1146332

คุณอาจจะติดอยู่ในp dup2(xxx, 2)นั้นp close(xxx)ที่เป็นค่าตอบแทนของxxx openนี่เป็นสิ่งที่ยุ่งยากไม่ควรใช้คำสั่งเหล่านี้กับกระบวนการที่ใช้เวลานานจนกว่าคุณจะแน่ใจว่าไม่มีตัวเลือกอื่น
Alan Curry

@ user1146332 มันเมื่อฉันพยายามมันเพราะผมเคย/dev/nullเป็นของฉันดังนั้นฉันไม่จำเป็นต้องerrfile O_CREATและO_WRONLYการเป็นมาโครไม่ว่าจะขยายหรือไม่ขึ้นอยู่กับว่า gdb หยุดกระบวนการที่บรรทัดที่มีสัญลักษณ์การดีบักพร้อมใช้งานและมีกำหนดแมโคร การฉีดโค้ดเข้าสู่กระบวนการด้วย gdb นั้นเป็นอันตรายและไม่มีใครควรคัดลอกคำสั่งเหล่านี้โดยไม่เข้าใจ
Alan Curry

@ AlanCurry ฉันไม่คิดว่า gdb จะขยายมาโครหากมีข้อมูลการแก้ไขข้อบกพร่องทั่วไป คุณต้องรวบรวมแหล่งที่มีธงพิเศษ (ดูที่นี่ ) นอกจากนี้ยังเป็นเรื่องธรรมดามากที่ระบบปฏิบัติการของคุณมีข้อมูลการดีบักรวมอยู่ด้วย (อนุญาตให้ข้อมูลนั้นขยายด้วยข้อมูลมาโคร) แต่ฉันเห็นด้วยกับคุณว่าการฉีดโค้ดโดยทั่วไปไม่แนะนำให้เลือก แต่อาจมีหลายกรณีที่คุณได้รับประโยชน์
user1146332
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.