Comment obtenir le PID d'un processus qui est pipé à un autre processus dans Bash?
j'essaie d'implémenter un simple serveur de log à Bash. Il devrait prendre un fichier comme paramètre et le servir sur un port avec netcat.
( tail -f & ) | nc -l -p 9977
mais le problème est que lorsque le netcat se termine, la queue est laissée derrière. (Clarification: si Je ne bifurque pas le processus de queue, il continuera à fonctionner pour toujours, même le netcat se termine.)
si je connais le PID de la queue, je pourrais le tuer après.
De toute évidence, à l'aide de $! retournera le PID de netcat.
Comment puis-je obtenir le PID du processus de queue?
12 réponses
Ecrivez le PID de tail au descripteur de fichier 3, puis capturez-le à partir de là.
( tail -f & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
une autre option: Utiliser une redirection vers subshell. Cela change l'ordre dans lequel les processus de fond sont lancés, donc $! donne PID du processus tail
.
tail -f > >(nc -l -p 9977) &
wait $!
que pensez-vous de ceci:
jobs -x echo %1
%1
est pour un premier emploi dans la chaîne d', %2
pour le deuxième, etc. jobs -x
remplace job specifier par PID.
cela fonctionne pour moi (SLES Linux):
tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"
l'astuce ps|grep|kill
mentionnée dans ce thread ne fonctionnerait pas si un utilisateur peut exécuter le script pour deux "instances" sur la même machine.
jobs -x echo %1
n'a pas fonctionné pour moi (page de manuel n'ayant pas le drapeau -x
) mais m'a donné l'idée d'essayer jobs -p
.
peut-être que vous pourriez utiliser un fifo , de sorte que vous pouvez capturer le pid du premier processus, par exemple:
FIFO=my_fifo
rm -f $FIFO
mkfifo $FIFO
tail -f > $FIFO &
TAIL_PID=$!
cat $FIFO | nc -l -p 9977
kill $TAIL_PID
rm -f $FIFO
enfin, j'ai réussi à trouver le processus de queue en utilisant ps
. Grâce à l'idée d'ennuikiller.
j'ai utilisé le ps
pour attraper la queue des args et la tuer. C'est un peu un piratage, mais ça a marché. :)
si vous pouvez trouver un meilleur moyen s'il vous plaît partager.
voici le script complet:
(La dernière version peut être trouvée ici: http://docs.karamatli.com/dotfiles/bin/logserver )
if [ -z "" ]; then
echo Usage: "151900920" LOGFILE [PORT]
exit -1
fi
if [ -n "" ]; then
PORT=
else
PORT=9977
fi
TAIL_CMD="tail -f "
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 }')
kill $TAIL_PID
}
trap "kill_tail; exit 0" SIGINT SIGTERM
while true; do
( $TAIL_CMD & ) | nc -l -p $PORT -vvv
kill_tail
done
ncat
se termine automatiquement tail -f
à la sortie (sur 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
une façon serait de simplement faire un ps-ef et grep pour tail avec votre script ppid
avez-vous essayé:
nc -l -p 9977 -c "tail -f "
(non testé)
Ou -e
avec un fichier si votre nc
n'a pas -c
. Vous devrez peut-être avoir un nc
compilé avec l'option GAPING_SECURITY_HOLE
. Oui, vous devez déduire les mises en garde appropriées de ce nom d'option.
vous pouvez stocker le pid de la commande tail
dans une variable en utilisant les redirections Bash I/O seulement (voir Comment obtenir le PID d'un processus dans un 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
ce n'est pas une réponse idéale, mais j'ai trouvé une solution pour contourner un démon logger sur lequel j'ai travaillé:
#!/bin/sh
tail -f /etc/service/rt4/log/main/current --pid=$$ | grep error
à partir de $info queue:
--pid=PID
with -f, terminate after process ID, PID dies
l'option -- pid à suivre est votre meilleur ami ici. Il vous permettra de contrôler totalement le pipeline en arrière-plan. lisez les options de la commande tail pour plus de résilience dans le cas où votre fichier est activement tourné par un autre processus qui pourrait vous laisser le suivi d'un inode inactif. L'exemple ci-dessous, bien qu'il ne soit pas utilisé pour traiter les données, démontre la restriction "imposée" sur la queue et la capacité de lui dire de quitter à tout moment. Il est utilisé pour mesurer la pression de service sur 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