¿Cómo obtener el PID de un proceso que se canaliza a otro proceso en Bash?

StackOverflow https://stackoverflow.com/questions/1652680

  •  22-07-2019
  •  | 
  •  

Pregunta

Estoy intentando 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 queda atrás. (Aclaración: si no bifurco el proceso final, continuará ejecutándose para siempre, incluso el netcat termina).

Si de alguna manera conozco el PID de la cola, podría matarlo después.
Obviamente, usando $! devolverá el PID de netcat.

¿Cómo puedo obtener el PID del proceso final?

¿Fue útil?

Solución

Escriba el PID de la cola en el descriptor de archivo 3 y luego captúrelo desde allí.

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

Otros consejos

Otra opción: usar una redirección a subshell. Esto cambia el orden en que se inician los procesos en segundo plano, por lo que $! da PID del proceso tail .

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

¿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.

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í (la página de manual no tiene el indicador -x ) pero me dio la idea de probar los trabajos - p .

Tal vez podría usar un fifo , para que pueda 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

Finalmente, he logrado encontrar el proceso de cola usando ps . Gracias a la idea de ennuikiller.

He usado el ps para arrancar la cola de los args y matarlo. Es una especie de truco, pero funcionó. :)

Si puede encontrar una mejor manera, comparta.

Aquí está el script completo:
(La última versión se puede encontrar aquí: http://docs.karamatli.com/dotfiles/bin/ servidor de registro )

if [ -z "$1" ]; then
    echo Usage: <*> 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 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

Una forma sería simplemente hacer un ps -ef y grep for tail con su script ppid

¿Has probado:

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

(no probado)

O -e con un archivo de script si su nc no tiene -c . Es posible que deba tener un nc que se compiló con la opción GAPING_SECURITY_HOLE . Sí, debe inferir las advertencias apropiadas del nombre de esa opción.

Puede almacenar el pid del comando tail en una variable utilizando solo redirecciones de E / S Bash (consulte Cómo obtener el PID de un proceso en una tubería ).

# 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

No es una respuesta ideal, pero encontré una solución para un demonio de registrador en el que trabajé:

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

desde $ info tail:

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

La opción --pid para seguir es tu mejor amigo aquí. Le permitirá un control total de la tubería que se ejecuta en segundo plano. lea las opciones del 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 "impuesta" restricción en la cola y la capacidad de decirle que salga en cualquier momento. Esto se utiliza 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

Puede usar el comando coproc dos veces.

El ejemplo dado se traduce en:

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"

(He arrojado un -v y un par de echo para resolver problemas)

Usar coproc se parece mucho a usar Popen () en varios otros lenguajes de script.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top