Jak wyświetlić wynik uruchomionego procesu w innej sesji bash?

199

Zostawiłem skrypt działający na zdalnej maszynie od czasu, gdy pracowałem nad nim lokalnie. Mogę połączyć się przez SSH z maszyną jako ten sam użytkownik i zobaczyć uruchomiony skrypt ps.

$ ps aux | grep ipcheck
myuser  18386  0.0  0.0  18460  3476 pts/0    S+   Dec14   1:11 /bin/bash ./ipchecker.sh

Po prostu wyświetla wyjście na standardowe wyjście w lokalnej sesji (uruchomiłem ./ipchecker.shz lokalnego okna terminala, bez przekierowania, bez użycia screenitp.).

Czy w ogóle z sesji SSH mogę wyświetlić dane wyjściowe tego uruchomionego polecenia (bez zatrzymywania go)?

Do tej pory najlepsze, co znalazłem, to użyć, strace -p 18386ale dostaję hordy tekstu lecącego w górę ekranu, który jest zbyt szczegółowy. Mogę zatrzymać, stracea następnie przeszukać dane wyjściowe i znaleźć tekst przeniesiony na standardowe wyjście, ale jest on bardzo długi i mylący, i oczywiście, gdy jest zatrzymany, mogę coś przeoczyć. Chciałbym znaleźć sposób, aby zobaczyć wyniki skryptu na żywo, tak jakbym pracował lokalnie.

Czy ktoś może to poprawić? Oczywistą odpowiedzią jest ponowne uruchomienie skryptu z przekierowaniem lub w screensesji itp. Nie jest to skrypt o znaczeniu krytycznym, więc mógłbym to zrobić. Uważam to raczej za zabawne ćwiczenie edukacyjne.

jwbensley
źródło
Czy Twój proces działa w wirtualnej konsoli lub w środowisku przypominającym GUI / Xterm?
jippie
4
Możesz ograniczyć wyjście strace do jednego strace -p 4232 -e write
wywołania systemowego
@jippie Na maszynie jest uruchomiony pełny GUI (Linux Mynt 13, XFCE), uruchomiłem terminal gnome.
jwbensley
3
Na tej stronie znajduje się co najmniej tuzin podobnych pytań. Poszukaj tutaj reptyr , aby znaleźć kilka z nich (i odpowiedź).
Stéphane Chazelas,

Odpowiedzi:

180

Jeśli wszystko, co chcesz zrobić, to szpiegować istniejący proces, możesz użyć strace -p1234 -s9999 -e writegdzie 1234 to identyfikator procesu. ( -s9999unika się obcięcia ciągów znaków do 32 znaków i writewywołania systemowego, które generuje dane wyjściowe). Jeśli chcesz wyświetlić tylko dane zapisane na określonym deskryptorze pliku, możesz użyć czegoś takiego, strace -p1234 -e trace= -e write=3aby zobaczyć tylko dane zapisane na deskryptorze pliku 3 ( -e trace=zapobiega systemowi połączenia z logowania). To nie da ci produkcji, która została już wyprodukowana.

Jeśli dane wyjściowe są przewijane zbyt szybko, możesz potokować je do pagera, takiego jak less, lub wysłać do pliku za pomocą strace -o trace.log ….

W wielu programach możesz przekierowywać kolejne dane wyjściowe za pomocą hackowania ptrace do bieżącego terminala lub do nowej sesji ekranowej. Zobacz Jak mogę odrzucić działający proces i powiązać go z nową powłoką ekranu? i inne powiązane wątki.

Należy pamiętać, że w zależności od konfiguracji systemu może być konieczne uruchomienie wszystkich tych stracekomend jako root, nawet jeśli proces jest wykonywany przez użytkownika bez żadnych dodatkowych uprawnień. (Jeśli proces działa jako inny użytkownik lub jest ustawiony jako setuid lub setgid, będziesz musiał uruchomić stracejako root). Większość dystrybucji zezwala jedynie na proces śledzenia jego elementów podrzędnych (zapewnia to umiarkowane korzyści bezpieczeństwa - zapobiega bezpośredniemu wstrzyknięciu złośliwego oprogramowania, ale nie zapobiega iniekcji pośredniej przez modyfikację plików). Jest to kontrolowane przez kernel.yama.ptrace_scomesysctl.

Gilles
źródło
18
Nie sądzę, że istnieje sposób na zawężenie wyjścia do zwykłego wyjścia ?
Jonah
3
Czy potrafisz wyjaśnić wszystkie argumenty?
Użytkownik
6
Było dużo odwrotnych ukośników i liczb w wielu wynikach, które otrzymywałem od nodejs; Czy są jakieś wskazówki dotyczące tego, w jakim kodowaniu mogą być? Było też mnóstwo zwykłego tekstu, co było wszystkim, czego potrzebowałem.
ThorSummoner,
3
„Czy potrafisz wyjaśnić wszystkie argumenty?” @ Użytkownik:man strace
Pistos
3
@RafaelMoni Program do robienia tego, o co prosisz, nazywa się debuggerem.
Gilles
139

Możesz uzyskać dostęp do danych wyjściowych za pośrednictwem procsystemu plików.

tail -f /proc/<pid>/fd/1

1= stdout, 2= stderr

tvlooy
źródło
7
Daje mi: „nie można otworzyć / proc / <mój pid> / fd / 1 do czytania: Brak takiego urządzenia lub adresu”.
Yaroslav Nikitenko
18
tak <mój pid> powinien być twoim identyfikatorem procesu
tvlooy
29
To nie zadziała, jeśli wyjście przejdzie do tty (lub zostanie przekierowane do /dev/null) - zadziała tylko wtedy, gdy wyjście zostanie przekierowane do pliku.
mattdm
1
Testowany na Ubuntu 16.04 i nie działa. W sesji robię: ping google.esw innej jako root: tail -f /proc/`pgrep ping`/fd/2i nic nie jest pokazywane.
david.perez
1
masz rację. Ponieważ fd 1 i 2 są dowiązaniami symbolicznymi do urządzenia / dev / pts. Nie możesz ogonić -fa pts urządzenia. Zaplanuj polecenie ping jako cronjob, a następnie zrób to samo. tail -f wtedy zadziała
tvlooy
9

W BSD możesz użyć, watchktóre szpieguje dany tty, np

watch /dev/pts/0

W Linuksie nie będzie to możliwe, jeśli proces nie był uruchamiany pod multiplekserem przed takimi jak screenlub tmux. Zobacz także: Reptyr: Dołącz działający proces do nowego terminala

Wydaje się, że jedynym sposobem jest debugowanie procesu (np strace, dtrace/ dtruss, gdb, lldb, itd.).

Ponieważ używałeś strace, aby pobrać dowolne znaczące dane wyjściowe, musisz przefiltrować według wyrażenia kwalifikującego (np. file), A następnie przeanalizować dane wyjściowe. Oto przykład:

strace -e trace=write -s1000 -fp 18386 2>&1 | grep -o '".\+[^"]"'

Co robi Drukuje operację zapisu procesu (długość 1000) określoną przez PID (użyj, pgrepaby znaleźć go po nazwie), przekierowuje standardowy błąd na wyjście (do filtrowania) i drukuje ciąg cudzysłowu.

Jeśli masz do czynienia z wyjściami binarnymi, możesz analizować znaki sekwencji specjalnych za pomocą read(z -r) i printf (z %b), np

while read -r -t1 line; do printf "%b" $line; done

Sprawdź help readwięcej parametrów (np. -nAby drukować po określonej ilości znaków, a nie nowej linii).

Oto bardziej kompletny przykład:

strace -e trace=write -s1000 -fp 18386 2>&1 \
| grep --line-buffered -o '".\+[^"]"' \
| grep --line-buffered -o '[^"]\+[^"]' \
| while read -r line; do
  printf "%b" $line;
done

Aby zapoznać się z przykładami wykorzystującymi dowolny proces, sprawdź: Jak parsować strace w powłoce na zwykły tekst? przy przepełnieniu stosu

kenorb
źródło
4
  1. Możliwe, że zerkniesz na ekran zdalny, używając miejsca, w ssh localhost 'DISPLAY=:0.0 xwd -root' | xwud -scalektórym localhostma zostać zastąpione poświadczenia logowania do zdalnego serwera oraz :0.0numeru wyświetlanego GUI.

  2. Użyj x11vnc, który jest serwerem VNC dla twojej sesji X na ekranie.

  3. Podczas uruchamiania na jednej z 6 konsol wirtualnych spróbuj sudo setterm -dump 2 -file /dev/stdout, gdzie zamienisz 2na odpowiedni vc.

jippie
źródło
4

Radzę zrobić nazwaną potok ( mkfifo), a następnie napisać do tego pliku. Następnie przeczytaj z niego. Zawsze możesz to zrobić za pomocą rzeczy takich jak tail, aby zminimalizować dane wyjściowe itp. Ilekroć wyczyścisz potok (odczyt z niego), zostanie on wyczyszczony, więc dane wyjściowe nie zostaną zachowane.

Inną opcją byłoby zapisanie wszystkiego do pliku (podobnie jak plik dziennika), a następnie przeanalizowanie go w dowolnym momencie. To byłoby preferowane działanie, jeśli chcesz zachować wszystkie dane wyjściowe.

polemon
źródło
3

Zawsze można uruchomić proces whith nohup i &

nohup rsync source_file dest_file &

Następnie możesz sprawdzić postęp z dowolnego tty za pomocą:

tail -f nohup.out

Działa mi to dobrze.

Pablo Luna
źródło
6
To pytanie dotyczy tego, jak wyświetlić wynik uruchomionego procesu alertu, a nie jak uruchomić proces w tle, jak sugeruje twoja odpowiedź
jwbensley
W rzeczywistości twoja: nohup wzmianka oświeca mnie! Dzięki!
Nam G VU,
1

Bardzo prostym sposobem na uzyskanie wyniku byłoby przechwycenie wyniku do pliku i dopasowanie tego pliku.

JEŚLI ZROBIĆ: ./ipcheck

INSTEAD DO: ./ipcheck> [zamień na nazwę pliku]

Spowoduje to utworzenie pliku wyjściowego, w którym znajduje się skrypt. Następnie z dowolnej innej powłoki bash możesz po prostu ogonić plik:

tail [zastąp swoją nazwą pliku] -f

MrAllen
źródło
Przekierowanie plików zwykle domyślnie korzysta z buforowania blokowego (patrz setbuf(3)), co może powodować tailproblemy.
thrig 26.04.17
5
To również nie pomaga w pytaniu, które dotyczyło sposobu wyświetlania wyników już uruchomionego procesu, a nie sposobu przekierowywania standardowego wyjścia dla nowego procesu.
jwbensley
1

Analizowanie danych wyjściowych strace:

Użyłem najwyższej odpowiedzi (z moim identyfikatorem procesu 28223) ...

> sudo strace -p28223 -s9999 -e write
...
write(9, "Info\nI\nCare\nabout", 55) = 55
...

Aby ustalić, na czym mi zależy write(9. (9 jest używane poniżej, prawdopodobnie jest to uchwyt pliku i może być inny dla twojego procesu). Potem napisałem szybki skrypt Ruby, aby go przeanalizować i wyświetlić.

Wklej następujące elementy do /usr/bin/parse_strace.rb

#!/usr/bin/ruby

num = ARGV[0]
STDIN.each { |line|
  if (line.match(/write\(#{ num },\s*"(.*?)"/)) then
    puts $1.split('\x').map { |s| s.to_i(16).chr }.join()
  end
}

Nie zapomnij chmod a+x /usr/bin/parse_strace.rb

Wywołuję strace -xx(generuje hex, więc wyrażenie regularne pasuje poprawnie), potokując (w tym STDERR) do mojego skryptu 9jako pierwszy argument.

sudo sh -c 'strace -xx -p28223 -s9999 -e write 2>&1 | parse_strace.rb 9'

I, voila, wyświetla oryginalny STDOUT procesu, nowe linie, kolor i wszystko!

Dołączanie do procesu STDOUT

Jeff Ward
źródło
0

nie możesz uzyskać identyfikatora procesu i komunikować się z nim z USR1,

$pgrep -l '^ipchecker.sh$'

który drukuje PID skryptu, a następnie użyj go do

$ kill -USR1 PID

Rozumiem, że USR1 jest sygnałem „zdefiniowanym przez użytkownika”, co oznacza, że ​​ktokolwiek stworzył program, może go użyć do oznaczenia „zamknij” lub „zrzuć logi” lub „drukuj foo tysiąc razy” lub cokolwiek innego.

Saeed
źródło