Перенаправити stderr з уже запущеного сценарію


14

Я вже кілька днів запускаю сценарій. Я перенаправив stdout $HOME/mylog, але не перенаправив stderr, оскільки думав, що на ньому нічого не буде. Раптом тисячі ліній почали виходити на жорсткіші, і я призупинив роботу. Чи є спосіб я перенаправляти stderr $HOME/myerrвідтепер, не потребуючи перезавантаження сценарію?

У мене є доступ до судо, і це ОС X.

Можливо, щось, що використовує захоплення dtools?

Я не можу втратити роботу, яку зробив сценарій досі, і перезапустити її з нуля. Чи є спосіб "скинути об'єкти пам'яті" на диск, заморозити програму, відредагувати змінні (наприклад, дескриптори файлів) та відновити новий контекст?


Відповіді:


12

Я думаю, що це можливо, якщо ви додасте процес відповідного інтерпретатора до gdb. Я спробував це за допомогою одного перламутрового Perl

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

і це працює, але, на жаль, не з аналогічним сценарієм bash.


Перш за все, ви повинні з'ясувати 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)закриває stderrподаний сценарій процесу (для stdoutфайлового сценарію - 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 і змушуйте процес зробити кілька системних викликів:

(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)дійсно працює на вашій машині?
користувач1146332

Ви можете вписатись у, p dup2(xxx, 2)а тоді, p close(xxx)де xxxє повернене значення open. Це складні речі, краще не використовувати ці команди в тривалому процесі, поки не будете впевнені, що іншого вибору немає.
Алан Каррі

@ user1146332 це робилося, коли я спробував це, тому що я використовував /dev/nullяк своє, errfileтому мені не потрібно O_CREAT. А O_WRONLYте, будучи макросом, розширюється він чи ні, залежить від того, чи gdb зупинив процес на лінії, де доступні символи налагодження та визначено макрос. Введення коду в процес з gdb небезпечно, і ніхто просто не повинен копіювати ці команди, не розуміючи їх.
Алан Каррі

@AlanCurry Я не думаю, що gdb розширює макроси, якщо доступна загальна інформація про налагодження. Ви повинні скласти джерела спеціальними прапорами (див. Тут ). Крім того, дуже рідко, що довільний виконуваний файл у вашій системі містить інформацію про налагодження (нехай поширюється одна інформація на макроінформацію). Але я згоден з вами, що введення коду, як правило, не доцільно, але можуть бути випадки, коли вам вигідно.
користувач1146332
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.