Przekieruj stderr z już działającego skryptu

14

Od kilku dni uruchamiam skrypt. Przekierowałem stdout na $HOME/mylog, ale nie przekierowałem stderr, ponieważ myślałem, że nic na tym nie będzie. Nagle na stderr zaczęły wychodzić tysiące linii, więc zawiesiłem pracę. Czy istnieje sposób, w jaki mogę teraz przekierowywać stderr $HOME/myerrbez konieczności restartowania skryptu?

Mam dostęp do sudo na pudełku i jest to OS X.

Być może coś przy użyciu pułapki dtools?

Nie mogę stracić pracy wykonanej dotychczas przez skrypt i zrestartować go od zera. Czy istnieje sposób na „zrzucenie obiektów w pamięci” na dysk, zamrożenie programu, edycję zmiennych (np. Deskryptorów plików) i wznowienie pracy z nowym kontekstem?

Robottinosino
źródło
możliwy duplikat Przekierowanie / grep'owanie istniejącej powłoki STDOUT
Gilles 'SO- przestań być zły'

Odpowiedzi:

12

Myślę, że jest to możliwe, jeśli dołączysz proces powiązanego interpretera do gdb. Próbowałem tego z tym linkiem perl

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

i działa, ale niestety nie z podobnym skryptem bash.


Przede wszystkim musisz ustalić PID tego procesu, którego wyjście chcesz uchwycić. Następnie uruchom gdbw innym terminalu i wykonaj następujące polecenia gdb

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

potem całe dane, które są zapisywane stderrjest przekierowany /abs/olu/te/path/filename, ponieważ

  • attach PID dołącza proces do gdb i zatrzymuje go
  • call close(2)zamyka stderrskryptowy skrypt procesu (dla stdoutskryptowego pliku jest 1)
  • call open(...) otwiera nowy plik i przyjmuje najniższą nieużywaną liczbę całkowitą dla nowo utworzonego skryptu plików i
  • detach PID kontynuuje proces

Przynajmniej na mojej maszynie. Pierwsze dwie linie są kompatybilne z POSIX, ale nie trzecia.

Drugi i trzeci argument openw trzeciej linii są udokumentowane w man 2 open. W moim przypadku 65 oznacza, że opennależy utworzyć plik i otworzyć plik tylko do zapisu, tj. O_WRONLY | O_CREAT(Zdefiniowany w fcntl.h). Trzeci argument mówi open, aby utworzyć plik z uprawnieniami do odczytu i zapisu dla użytkownika, tj. S_IWUSR | S_IRUSR(Zdefiniowany w sys/stat.h). Może więc musisz samodzielnie znaleźć odpowiednie wartości na swoim komputerze.

użytkownik1146332
źródło
To zadziałało niesamowicie dobrze ... czapki z głów !!
Robottinosino,
8

To prymitywna odpowiedź i mam nadzieję, że ktoś inny poradzi sobie lepiej, ale jeśli nie pojawią się żadne inne pomysły, dołącz gdb i zmuś proces do wykonania kilku wywołań systemowych:

(gdb) attach 12345 # target PID
(gdb) p close(2)
(gdb) p open("errfile", O_WRONLY)
(gdb) c
Alan Curry
źródło
Fajne Nie wiedziałem, że gdb może to zrobić. Czy jest jakiś sposób na wymuszenie określonego numeru deskryptora pliku? Powiedzmy, że jeśli FD 1 jest nieużywany, a open()chwyta FD 1? A może po prostu dzwonisz dup()kilka razy?
Patrick
czy p open("errfile", O_WRONLY)naprawdę działają na komputerze?
user1146332
Możesz wstawić a, p dup2(xxx, 2)a następnie p close(xxx)gdzie xxxjest zwracana wartość open. To trudna sprawa, lepiej nie używać tych poleceń w długotrwałym procesie, dopóki nie będziesz pewien, że nie ma innego wyjścia.
Alan Curry
@ user1146332 zrobiło to, kiedy próbowałem, ponieważ użyłem go /dev/nulljako mojego, errfilewięc nie potrzebowałem O_CREAT. A O_WRONLYbycie makrem, czy się rozwija, czy nie, zależy od tego, czy gdb zatrzymał proces w linii, w której dostępne są symbole debugowania i makro jest zdefiniowane. Wstrzykiwanie kodu do procesu za pomocą gdb jest niebezpieczne i nikt nie powinien kopiować tych poleceń bez ich zrozumienia.
Alan Curry
@AlanCurry Nie sądzę, że gdb rozwija makra, jeśli dostępne są ogólne informacje debugowania. Musisz skompilować źródła ze specjalnymi flagami (patrz tutaj ). Poza tym bardzo rzadko zdarza się, że dowolny plik wykonywalny w twoim systemie zawiera informacje debugowania (pozwól, aby informacje te zostały rozszerzone o informacje makro). Ale zgadzam się z tobą, że wstrzyknięcie kodu nie jest na ogół zalecane, ale mogą zdarzyć się przypadki, w których skorzystasz.
user1146332,