Как получить PID процесса, который передается другому процессу в Bash?
Вопрос
Я пытаюсь реализовать простой сервер журналов в 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 () в различных других языках сценариев.