Как получить PID процесса, который передается другому процессу в Bash?

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

  •  22-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

jobs -x echo %1

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

Это работает для меня (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 - р .

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

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

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

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

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

Вот полный скрипт:
(Последнюю версию можно найти здесь: http://docs.karamatli.com/dotfiles/bin/. LogServer )

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 автоматически завершает работу 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

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

Попытался ли ты:

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

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

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

Вы можете сохранить 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

Не идеальный ответ, но я нашел обходной путь для демона регистратора, над которым я работал:

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

из хвоста $ info:

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

Опция --pid tail - ваш лучший друг здесь. Это позволит вам полностью контролировать работу трубопровода в фоновом режиме. прочитайте параметры команды tail для большей устойчивости в случае, если ваш файл активно вращается другим процессом, что может привести к тому, что вы перестанете отслеживать неактивный inode. Приведенный ниже пример, хотя и не используется для обработки данных, демонстрирует «навязанный» ограничение на хвост и возможность сказать ему, чтобы выйти в любое время. Это используется для измерения сервисного давления на 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

Вы можете дважды использовать команду coproc .

Данный пример переводится как:

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"

(Я добавил туда -v и пару echo для устранения неполадок.)

Использование coproc во многом похоже на использование Popen () в различных других языках сценариев.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top