Obtém o PID de qualquer comando na sequência canalizada de comandos em segundo plano

9

Se, em bash , eu executar:

cmd1 | cmd2 | ... | cmdi | ... | cmdn &

em que cmd{1..n} pode não ser diferente, como obtenho o PID de cmdi ? Como alternativa, como posso sinalizar o processo cmdi ? (Por exemplo, envie SIGUSR1 ?) pkill / pgrep , pidof etc. não parecem boas respostas, pois outras instâncias de cmdi talvez estejam sendo executadas, inclusive como parte do mesmo pipeline. jobs -p dá o PID de cmd1 , para mim.

i pode ser qualquer coisa em {1..n} .

    
por muru 18.09.2014 / 02:07

3 respostas

6

Para a versão original da pergunta, quando apenas o PID do último comando era desejado, a variável especial $! é perfeita.

foo | bar | baz &
baz_pid=$!

Não há acesso fácil semelhante aos PIDs dos outros processos.

Demorou muito para que $pipestatus (zsh) e $PIPESTATUS (bash) fossem adicionados, finalmente nos dando acesso a todos os status de saída em um pipeline, além do $? para o último um que existe desde o shell Bourne original. Talvez algo análogo aconteça com $! eventualmente.

    
por 18.09.2014 / 02:14
4

Acho que você poderia fazer algo como sugerido aqui .

(ls -l | echo "Hello" | df -h & echo $! >&3 ) 3>pid

Aqui no exemplo acima, eu recuperei o pid do terceiro processo canalizado e o anotei no arquivo pid. Eu poderia anotar isso para qualquer processo de canalização.

    
por 18.09.2014 / 02:45
1

Uma solução não portável e específica para Linux poderia ser rastrear os processos usando os canais que os conectam. Podemos obter os PIDs dos primeiros comandos ( jobs -p ) e last ( $! ) no pipeline. Usando o PID, esse script pode fazer o trabalho:

#! /bin/bash

PROC=$1
echo $PROC

if [[ $(readlink /proc/$PROC/fd/1) =~ ^pipe: ]]
then
    # Assuming first process in chain...
    NEXT_FD=1
elif [[ $(readlink /proc/$PROC/fd/0) =~ ^pipe: ]]
then
    # Last process in chain...
    NEXT_FD=0
else
    # Doesn't look like a pipe.
    exit
fi

NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)

while [[ $NEXT_PROC_PIPE =~ ^pipe: ]] 
do
    PROC=$(find /proc/*/fd -type l -printf "%p/%l\n" 2>/dev/null | awk -F'/' '($6 == "'"$NEXT_PROC_PIPE"'") && ($3 != "'$PROC'" ) {print $3}')
    NEXT_PROC_PIPE=$(readlink /proc/$PROC/fd/$NEXT_FD)
    echo $PROC
done
    
por 18.09.2014 / 03:50