it-swarm.com.de

Wie erhalte ich die PID eines Prozesses, der an einen anderen Prozess in Bash geleitet wird?

Ich versuche, einen einfachen Protokollserver in Bash zu implementieren. Es sollte eine Datei als Parameter verwenden und auf einem Port mit netcat bereitstellen.

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

Das Problem ist jedoch, dass das Ende des netcat hinter dem Laufen bleibt. (Erläuterung: Wenn ich den Tail-Prozess nicht abspreche, wird er für immer weiter ausgeführt, selbst wenn der netcat beendet wird.) 

Wenn ich die PID des Schwanzes irgendwie kenne, könnte ich ihn danach töten.
Natürlich mit $! gibt die PID von netcat zurück.

Wie kann ich die PID des Schwanzprozesses erhalten?

44

Schreiben Sie die PID von tail in den Dateideskriptor 3 und erfassen Sie sie von dort aus.

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

Eine weitere Option: Verwenden Sie eine Weiterleitung zur Subshell. Dies ändert die Reihenfolge, in der Hintergrundprozesse gestartet werden, also $! gibt die PID des tail-Prozesses an.

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

wie wäre es damit:

jobs -x echo %1

%1 ist für den ersten Job in der Kette, %2 für den zweiten usw. jobs -x ersetzt den Jobbezeichner durch die PID.

11
przemas

Das funktioniert für mich (SLES Linux):

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

Der in diesem Thread erwähnte ps|grep|kill-Trick funktioniert nicht, wenn ein Benutzer das Skript für zwei "Instanzen" auf demselben Computer ausführen kann.

jobs -x echo %1 hat für mich nicht funktioniert (Manpage hat nicht das -x-Flag), gab mir aber die Idee, jobs -p auszuprobieren.

9
James Shau

Vielleicht könnten Sie ein fifo verwenden, damit Sie die PID des ersten Prozesses erfassen können, z.

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
6
martin clayton

ncat beendet tail -f automatisch beim Beenden (unter 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
2
pjil

Schließlich habe ich es geschafft, den Tail-Prozess mithilfe von ps zu finden. Dank der Idee von ennuikiller.

Ich habe die ps benutzt, um den Schwanz von den Args zu greifen und zu töten. Es ist eine Art Hack, aber es hat funktioniert. :)

Wenn Sie einen besseren Weg finden, teilen Sie uns bitte.

Hier ist das komplette Skript:
(Neueste Version finden Sie hier: http://docs.karamatli.com/dotfiles/bin/logserver )

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
2

Sie können die PID des Befehls tail in einer Variablen nur mit Bash-E/A-Umleitungen speichern (siehe So erhalten Sie die PID eines Prozesses in einer 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
1
chad

Hast du es versucht:

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

(ungetestet)

Oder -e mit einer Skriptdatei, falls Ihre nc keinen -c hat. Möglicherweise muss eine nc vorhanden sein, die mit der Option GAPING_SECURITY_HOLE kompiliert wurde. Ja, Sie sollten aus diesem Optionsnamen entsprechende Vorbehalte ableiten.

1

Eine Möglichkeit wäre, einfach ein ps -ef und grep for tail mit Ihrem Skript ppid auszuführen

1
ennuikiller

Keine ideale Antwort, aber ich habe einen Workaround für einen Logger-Daemon gefunden, an dem ich gearbeitet habe:

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

von $ info tail:

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

Sie können den Befehl coproc zweimal verwenden.

Das gegebene Beispiel übersetzt in:

coproc TAIL { tail -f $1; }; exec {TAIL[1]}<&-
coproc NC { nc -v -l -p 9977; } <&"${TAIL[0]}" >&1
wait $NC_PID; echo "nc exit code: $!"
kill $TAIL_PID; echo "done"

(Ich habe einen -v und ein paar echo zur Fehlerbehebung dort hineingeworfen.)

Die Verwendung von coproc fühlt sich sehr an wie das Verwenden von Popen () in verschiedenen anderen Skriptsprachen.

0
pipe_of_sharks

Die Option --pid to tail ist hier dein bester Freund. Damit haben Sie die vollständige Kontrolle über die Pipeline, die im Hintergrund ausgeführt wird. Lesen Sie die Tail-Befehlsoptionen, um die Ausfallsicherheit zu erhöhen, falls Ihre Datei aktiv von einem anderen Prozess gedreht wird, wodurch Sie möglicherweise einen inaktiven Inode verfolgen. Das folgende Beispiel zeigt, obwohl es nicht für die Verarbeitung der Daten verwendet wird, die "auferlegte" Einschränkung des Schwanzes und die Fähigkeit, es jederzeit zu beenden. Dies wird zur Messung des Betriebsdrucks an httpd verwendet.

  # 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
0
Danny