¿Cómo obtener el PID de un proceso que se canaliza a otro proceso en Bash?
pipe tail (12)
Estoy tratando de implementar un servidor de registro simple en Bash. Debe tomar un archivo como parámetro y servirlo en un puerto con netcat.
( tail -f $1 & ) | nc -l -p 9977
Pero el problema es que cuando el netcat termina, la cola se deja correr. (Aclaración: si no bifurco el proceso de cola, continuará funcionando para siempre incluso cuando termine netcat).
Si de alguna manera conozco el PID de la cola, entonces podría matarlo después.
Obviamente, usando $! devolverá el PID de netcat.
¿Cómo puedo obtener el PID del proceso de cola?
Escriba el PID de cola en el descriptor de archivo 3, y luego capturelo desde allí.
( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
Esto funciona para mí (SLES Linux):
tail -F xxxx | tee -a yyyy &
export TAIL_PID=`jobs -p`
# export TEE_PID="$!"
El truco ps|grep|kill
mencionado en este hilo no funcionaría si un usuario puede ejecutar el script para dos "instancias" en la misma máquina.
jobs -x echo %1
no funcionó para mí (página de manual que no tiene el -x
) pero me dio la idea de probar jobs -p
.
Finalmente, he logrado encontrar el proceso de cola usando ps
. Gracias a la idea de ennuikiller.
He usado el ps
para grep tail de los args y lo mato. Es una especie de truco, pero funcionó. :)
Si puede encontrar una mejor manera, por favor comparta.
Aquí está el guión completo:
(La última versión se puede encontrar aquí: 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
Has probado:
nc -l -p 9977 -c "tail -f $1"
(no probado)
O bien, con un archivo de comandos si su nc
no tiene -c
. Es posible que deba tener una nc
compilada con la opción GAPING_SECURITY_HOLE
. Sí, debe inferir advertencias apropiadas de ese nombre de opción.
La opción --pid a la cola es tu mejor amigo aquí. Le permitirá un control total de la tubería que se ejecuta en segundo plano. lea las opciones de comando de cola para obtener más resistencia en caso de que su archivo sea rotado activamente por otro proceso que podría dejarlo siguiendo un inodo inactivo. El siguiente ejemplo, aunque no se utiliza para procesar los datos, demuestra la restricción "impuesta" en la cola y la capacidad de indicarle que salga en cualquier momento. Esto se usa para medir la presión del servicio en 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
No es una respuesta ideal, pero encontré una solución para un daemon logger en el que trabajé:
#!/bin/sh
tail -f /etc/service/rt4/log/main/current --pid=$$ | grep error
de $ info tail:
--pid=PID
with -f, terminate after process ID, PID dies
Otra opción: use un redireccionamiento a subshell. Esto cambia el orden en que se inician los procesos en segundo plano, ¡así que $! da PID del proceso de tail
.
tail -f $1 > >(nc -l -p 9977) &
wait $!
Puede almacenar el comando pid del tail
en una variable usando solo redirecciones Bash I / O (consulte Cómo obtener el PID de un proceso en una canalización ).
# 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
Qué tal esto:
jobs -x echo %1
%1
es para el primer trabajo en la cadena, %2
para el segundo, etc. jobs -x
reemplaza el especificador de trabajo con PID.
Tal vez podrías usar un fifo para que puedas capturar el pid del primer proceso, por ejemplo:
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
Una forma sería simplemente hacer un ps -ef y grep para cola con su script ppid
ncat
termina automáticamente tail -f
al salir (en 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