Wie die PID eines Prozesses erhalten, die zu einem anderen Prozess in Bash geleitet wird?
Frage
Ich versuche, einen einfachen Log-Server in Bash zu implementieren. Es sollte eine Datei als Parameter nehmen und es auf einem Port mit netcat dienen.
( tail -f $1 & ) | nc -l -p 9977
Aber das Problem ist, dass, wenn der netcat endet, Schweif hinter laufen gelassen wird. (Zur Verdeutlichung:. Wenn ich es nicht den Schwanz Prozess Gabel wird auch weiterhin immer noch die netcat beendet laufen)
Wenn ich irgendwie die PID des Schwanzes weiß dann könnte ich es danach töten.
Offensichtlich mit $! wird die PID netcat zurück.
Wie kann ich die PID des Schwanzes Prozess bekommen?
Lösung
Schreiben Schwanz PID Dateideskriptor 3 und erfassen sie dann von dort aus.
( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
Andere Tipps
Eine weitere Option: Verwenden Sie eine Umleitung Subshell. Dadurch ändert sich die Reihenfolge, in der Hintergrund-Prozesse gestartet werden, so $! PID des tail
Prozess gibt.
tail -f $1 > >(nc -l -p 9977) &
wait $!
Wie wäre es dieses:
jobs -x echo %1
%1
für den ersten Job in der Kette ist, %2
für die zweite usw. jobs -x
ersetzt Job Spezifizierer mit PID.
Dies funktioniert für mich (SLES Linux):
tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"
Der ps|grep|kill
Trick in diesem Thread erwähnt würde nicht funktionieren, wenn ein Benutzer das Skript für zwei „Instanzen“ auf der gleichen Maschine laufen kann.
jobs -x echo %1
nicht für mich arbeiten (man-Seite nicht die -x
Flagge mit), aber gab mir die Idee jobs -p
zu versuchen.
Vielleicht könnten Sie ein Fifo verwenden, so dass Sie die pid des ersten Prozesses erfassen , zum Beispiel:
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
Schließlich habe ich es geschafft, die Schwanz-Prozess zu finden ps
verwenden. Dank der Idee von ennuikiller.
Ich habe die ps
grep Schwanz von dem args verwendet und es zu töten. Es ist eine Art ein Hack, aber es funktionierte. :)
Wenn Sie einen besseren Weg finden, bitte teilen.
Dies ist die 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
ncat
automatisch tail -f
auf exit beendet (auf 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
Eine Möglichkeit wäre, einfach tun, um einen ps -ef und grep für Schwanz mit Ihrem Skript ppid
Haben Sie versucht:
nc -l -p 9977 -c "tail -f $1"
(ungetestet)
oder -e
mit einem Script wenn Ihr nc
nicht über -c
. Sie können einen nc
haben, die mit der GAPING_SECURITY_HOLE
Option kompiliert wurde. Ja, Sie sollten entsprechende Einsprüche von dieser Option Namen entnehmen.
Sie können speichern Sie die pid des tail
Befehls in einer Variablen mit Schlag-I / O-Umleitungen nur (siehe Wie die PID eines Prozesses in einer Pipeline zu bekommen).
# 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
Keine ideale Antwort, aber ich fand für einen Logger-Daemon eine Abhilfe, die ich arbeitete an:
#!/bin/sh
tail -f /etc/service/rt4/log/main/current --pid=$$ | grep error
von $ info Schwanz:
--pid=PID
with -f, terminate after process ID, PID dies
Die --pid Option Schwanz ist dein bester Freund hier. Es wird Ihnen die Kontrolle über die Pipeline im Hintergrund laufen insgesamt ermöglichen. lesen Sie die tail-Befehlsoptionen für mehr Elastizität, falls Ihre Datei aktiv von einem anderen Prozess gedreht wird, die Sie verlassen könnte eine inaktive inode Tailing. Das folgende Beispiel, wenn auch nicht verwendet, die Daten zu verarbeiten zeigen die „auferlegt“ Beschränkung des Schwanz und die Fähigkeit, ihm zu sagen, zu jeder Zeit zu beenden. Dieser wird zur Messung des Betriebsdruckes auf 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
Sie könnten den coproc
Befehl zweimal verwendet werden.
Das gegebene Beispiel übersetzt:
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"
(I ein -v
und ein paar echo
da drin für die Fehlerbehebung geworfen haben.)
coproc
Mit fühlt sich viel wie mit Popen () in verschiedenen anderen Skriptsprachen.