2009-10-30 13 views
37

Próbuję zaimplementować prosty serwer dziennika w Bash. Powinien pobrać plik jako parametr i podać go na porcie z netcat.Jak uzyskać identyfikator PID procesu, który jest podłączony do innego procesu w Bash?

(tail -f $1 &) | nc -l -p 9977 

Ale problem polega na tym, że gdy netcat się kończy, ogon pozostaje włączony. (Wyjaśnienie: jeśli nie rozwiążę procesu ogona, to będzie on działał wiecznie, nawet netcat się zakończy.)

Jeśli w jakiś sposób znam PID ogona, to mogę go potem zabić.
Oczywiście, używając $! zwróci PID netcat.

Jak mogę uzyskać PID procesu ogon?

+0

Co stanie się, jeśli nie użyjesz '&'? 'tail -f' powinien po prostu tam poczekać. Nie rozumiem, do czego służy '&', chociaż wygląda na to, że jest częścią większego skryptu. W każdym razie, jeśli zabijesz rurę, myślę, że ogon by wtedy umarł (o ile nie miałeś tła). –

+0

z mojego rozumienia powłok, iw tym przypadku jest używany z jego znaczeniem "zacznij od tła". Przynajmniej takie zachowanie widzę teraz, próbując zastosować to rozwiązanie do mojego własnego, podobnego problemu. – starturtle

Odpowiedz

27

Wpisywanie ogon do pliku deskryptora 3, a następnie uchwycić go stamtąd.

(tail -f $1 & echo $! >&3) 3>pid | nc -l -p 9977 
kill $(<pid) 
+4

Użyłem wariantu: '(tail -f $ 1 & echo $!> Pid) | nc -l -p 9977' (nie wiem, dlaczego użycie deskryptora 3 plików pomogłoby w ostatecznym przekierowaniu do pliku) – Wernight

+0

Nie wiem dlaczego, ale moje rozwiązanie kończy się niepowodzeniem po wyprowadzeniu kilku linii dziennika. Prawdopodobnie, gdy bufor na rury jest pełny. Wtedy początkowy proces wydaje się czekać na przetworzenie rury. – Wernight

1

Jednym ze sposobów byłoby po prostu zrobić -ef ps i grep na ogonie z PPID skryptu

+0

Nie mogłem go uzyskać za pomocą ppid, ponieważ jest on odłączany, gdy go rozwidniam w podpowłoce. Ale udało mi się go pobrać przy użyciu parametru args programu 'ps'. –

6

Może użyć fifo, dzięki czemu można uchwycić pid pierwszym procesie, np

FIFO=my_fifo 

rm -f $FIFO 
mkfifo $FIFO 

tail -f $1 > $FIFO & 
TAIL_PID=$! 

cat $FIFO | nc -l -p 9977 

kill $TAIL_PID 

rm -f $FIFO 
+0

Tak, próbowałem tego wcześniej. Problem z używaniem fifo jest taki sam: rura nigdy się nie kończy, więc kot zostaje uruchomiony nawet kończy się netcat. Kontrolka pozostaje w linii kotów, więc nigdy nie wykonuje zabójstwa. –

+0

To dziwne - powyższy skrypt działał idealnie dla mnie na Mac OS X. Jedyną różnicą było to, że pominąłem flagę "-p" dla nc. –

+0

Może to problem z platformą (jak obchodzić się z rurami). Próbuję go na komputerze z systemem Linux. dzięki za odpowiedź! –

1

Czy próbowałeś:

nc -l -p 9977 -c "tail -f $1" 

(niesprawdzone)

Lub -e ze skryptem, jeśli twój nc nie ma -c. Być może musisz mieć nc, który został skompilowany z opcją GAPING_SECURITY_HOLE. Tak, powinieneś wywnioskować odpowiednie zastrzeżenia z tej nazwy opcji.

+0

Och, nigdy o tym nie myślałem. Szkoda, że ​​to nie zadziałało :) Ale nadal nie kończy się z powodu natury "tail -f" –

+0

A może bez '-f'? –

+0

bez -f, jest OK. Ale chcę służyć w czasie rzeczywistym. –

2

Wreszcie udało mi się znaleźć proces ogona za pomocą ps. Dzięki pomysłowi z ennuikiller.

Użyłem ps, aby oderwać ogon od argumentów i zabić go. To jest hack, ale zadziałało. :)

Jeśli możesz znaleźć lepszy sposób, proszę udostępnij.

Oto pełna scenariusz:
(Najnowszą wersję można znaleźć tutaj: http://docs.karamatli.com/dotfiles/bin/logserver) PID

if [ -z "$1" ]; then 
    echo Usage: $0 LOGFILE [PORT] 
    exit -1 
fi 
if [ -n "$2" ]; then 
    PORT=$2 
else 
    PORT=9977 
fi 

TAIL_CMD="tail -f $1" 

function kill_tail { 
    # find and kill the tail process that is detached from the current process 
    TAIL_PID=$(/bin/ps -eo pid,args | grep "$TAIL_CMD" | grep -v grep | awk '{ print $1 }') 
    kill $TAIL_PID 
} 
trap "kill_tail; exit 0" SIGINT SIGTERM 

while true; do 
    ($TAIL_CMD &) | nc -l -p $PORT -vvv 
    kill_tail 
done 
+0

Czy nie powinien być dostępny PID polecenia ogon w '$!', Aby po prostu zrobić 'kill $!' Zamiast 'kill_tail'? – tripleee

2

ncat automatycznie kończy tail -f na wyjściu (w systemie Mac OS X 10.6.7)!

# simple log server in Bash using ncat 
# cf. http://nmap.org/ncat/ 
touch file.log 
ncat -l 9977 -c "tail -f file.log" </dev/null # terminal window 1 
ncat localhost 9977 </dev/null     # terminal window 2 
echo hello > file.log       # terminal window 3 
1

można przechowywać PID komendy tail w zmiennej za pomocą atakujących I/O przekierowania tylko (patrz How to get the PID of a process in a pipeline).

# terminal window 1 
# using nc on Mac OS X (FreeBSD nc) 
: > /tmp/foo 
PID=$({ { tail -f /tmp/foo 0<&4 & echo $! >&3 ; } 4<&0 | { nc -l 9977 ;} & } 3>&1 | head -1) 
kill $PID 

# terminal window 2 
nc localhost 9977 

# terminal window 3 
echo line > /tmp/foo 
28

Inna opcja: użyj przekierowania do podpowłoki. Zmienia to kolejność uruchamiania procesów w tle, więc $! daje PID procesu tail.

tail -f $1 > >(nc -l -p 9977) & 
wait $! 
+1

Zaletą tego podejścia jest to, że po odczekaniu $? posiada również status wyjścia –

+0

Wydaje się to być najczystszym podejściem przez długie ujęcie. Czy zmienia wszystko (w porównaniu ze standardową orurowaniem) z perspektywy innego procesu niż kolejność startu? – wlritchi

+8

W rzeczywistości składnia tego przekierowania jest błędna (chociaż zasada jest poprawna). '> (foo)' zastępuje nazwę nowego deskryptora pliku, podczas gdy '>> (foo)' faktycznie przekierowuje do niego wyjście. Chcesz, żeby pierwsza linia była 'tail -f $ 1>> (nc -l -p 9977) &'. – wlritchi

9

jak o tym:

jobs -x echo %1 

%1 jest do pierwszej pracy w sieci, %2 na sekundę itp jobs -x zastępuje specyfikator pracy z PID.

+1

To musi być najczystsze i najkrótsze rozwiązanie "jak zdobyć pid każdego procesu wcześniej w łańcuchu" Dziękuję! Działa również z "&" otrzymaniem pid procesu wcześniej w łańcuchu, który działa w tle! Na przykład. 'dd if =/dev/urandom bs = 1M liczba = 1024 | sha1sum & pid = $ (zadania - x echo% 1) ' ' kill -USR1 $ pid' – JATothrim

0

nie idealne rozwiązanie, ale znalazłem obejście demon rejestratora pracowałem na:

#!/bin/sh 
tail -f /etc/service/rt4/log/main/current --pid=$$ | grep error 

z informacji $ Ogon:

--pid=PID 
      with -f, terminate after process ID, PID dies 
8

Działa to dla mnie (SLES Linux):

tail -F xxxx | tee -a yyyy & 
export TAIL_PID=`jobs -p` 
# export TEE_PID="$!" 

ps|grep|kill trik wspomniano w tym wątku nie będzie działać, jeśli użytkownik może uruchomić skrypt dwa "wystąpienia" na tym samym komputerze.

jobs -x echo %1 nie działa dla mnie (strona man nie ma flagi -x), ale dał mi pomysł wypróbowania jobs -p.

0

Opcja --pid do ogona jest twoim najlepszym przyjacielem tutaj. Pozwoli to na całkowitą kontrolę nad przebiegiem rurociągu w tle. przeczytaj opcje poleceń ogonowych, aby uzyskać większą odporność, na wypadek, gdyby plik został aktywnie obrócony przez inny proces, który może spowodować, że będziesz śledzić nieaktywny i-węzeł. Poniższy przykład, choć nie jest używany do przetwarzania danych, demonstruje "nałożone" ograniczenie na ogonie i możliwość nakazania mu wyjścia w dowolnym momencie. Służy do pomiaru ciśnienia usługi na httpd.

# Set the tail to die in 100 second even if we die unexpectedlly. 
sleep 100 & ; ctlpid=$! 
tail -q -n 0 --follow=name --retry --max-unchanged-stats=1 --pid=$ctlpid -f /var/log/httpd/access_log 2>/dev/null | wc –l > /tmp/thisSampleRate & 
…. Do some other work 
…. Can kill the pipe at any time by killing $ctlpid 
…. Calculate preassure if /tmp/thisSampleRate is ready 
Powiązane problemy