Как получить PID процесса, который передается другому процессу в Bash? - PullRequest
47 голосов
/ 31 октября 2009

Я пытаюсь реализовать простой сервер журналов в Bash. Он должен принимать файл в качестве параметра и передавать его через порт с помощью netcat.

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

Но проблема в том, что когда netcat завершает работу, tail остается позади. (Уточнение: если я не разветвляюсь, процесс хвоста будет продолжаться вечно, даже если netcat завершит работу.)

Если бы я как-то знал PID хвоста, я мог бы потом его убить.
Очевидно, используя $! вернет PID netcat.

Как я могу получить PID хвостового процесса?

Ответы [ 13 ]

36 голосов
/ 08 ноября 2011

Другой вариант: использовать перенаправление на subshell. Это меняет порядок запуска фоновых процессов, поэтому $! дает PID tail процесса.

tail -f $1 > >(nc -l -p 9977) &
wait $!
35 голосов
/ 24 сентября 2010

Записать PID хвоста в файловый дескриптор 3, а затем перехватить его оттуда.

( tail -f $1 & echo $! >&3 ) 3>pid | nc -l -p 9977
kill $(<pid)
13 голосов
/ 18 января 2012

как насчет этого:

jobs -x echo %1

%1 для первого задания в цепочке, %2 для второго и т. Д. jobs -x заменяет спецификатор задания на PID.

9 голосов
/ 20 августа 2012

Это работает для меня (SLES Linux):

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

Уловка ps|grep|kill, упомянутая в этой теме, не будет работать, если пользователь сможет запустить сценарий для двух «экземпляров» на одном компьютере.

jobs -x echo %1 у меня не сработало (на странице man нет флага -x), но мне предложили попробовать jobs -p.

7 голосов
/ 31 октября 2009

Может быть, вы могли бы использовать fifo , чтобы вы могли захватить pid первого процесса, например ::100100

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
2 голосов
/ 07 июля 2011

ncat автоматически завершается tail -f при выходе (в 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 голосов
/ 31 октября 2009

Наконец, мне удалось найти хвостовой процесс, используя ps. Благодаря идее от ennuikiller.

Я использовал ps, чтобы убрать хвост из аргов и убить его. Это что-то вроде взлома, но это сработало. :)

Если вы можете найти лучший способ, пожалуйста, поделитесь.

Вот полный скрипт:
(Последняя версия может быть найдена здесь: 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
1 голос
/ 18 сентября 2011

Вы можете сохранить pid команды tail в переменной, используя только перенаправления Bash I / O (см. Как получить PID процесса в конвейере ).

# 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 голос
/ 31 октября 2009

Вы пробовали:

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

(непроверенные)

или -e с файлом сценария, если у вашего nc нет -c. Возможно, вам придется иметь nc, который был скомпилирован с опцией GAPING_SECURITY_HOLE. Да, вы должны сделать соответствующие предостережения по названию опции.

1 голос
/ 31 октября 2009

Один из способов - сделать ps -ef и grep для tail с помощью скрипта ppid

.
...