Arka plandaki borulu komut dizisindeki herhangi bir komutun PID'sini alma


11

In bash, ben çalıştırırsanız:

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

nerede cmd{1..n}farklı olmayabilir, nasıl PID alabilirim cmdi? Alternatif olarak, cmdisüreci nasıl işaret edebilirim ? (Örneğin, gönderilsin mi SIGUSR1?) pkill/ pgrep, pidofVb. İyi yanıtlar gibi görünmez, çünkü cmdiaynı boru hattının bir parçası da dahil olmak üzere belki de çalışan diğer örnekler . benim jobs -piçin PID veriyor cmd1.

iherhangi bir şey olabilir {1..n}.



1
@ G-Man Açıklamak ister misiniz? Sadece yüzeysel benzerlik görüyorum ve Ramesh'in cevabında açıkladığım gibi, komutlar dizisini değiştirmek pek kullanışlı değil.
muru

Yüzeysel benzerlik? cat /var/run/out | nc -l 8080sadece yüzeysel olarak benzer etmek cmd1 | cmd2? Çıplak kemikler boru hattını yazmak ve daha sonra PID'leri kurtarmak istediğiniz kısıtlamanız (1) soruda belirtilmemiş ve (2) iyi, genel bir çözüme izin verme olasılığı düşüktür.
G-Man, 'Monica'yı Eski

@ G-Man Aksine, basitliğin belirtilmediği kısıtlamalar uyguluyorsunuz. cmd1 | cmd2her iki PID'nin de kolayca elde edilebildiği çok özel bir durumdur. N hakkında bir şey söyledim mi? Öyleyse neden n = 2 olduğunu varsayalım? Cmdi'nin ne olduğu hakkında bir şey söyledim mi? Peki neden cmdi'yi değiştirebileceğimi varsayalım? Genel bir çözüm istiyorum ve siz kısıtlamalar uyguluyorsunuz.
muru

Yanıtlar:


6

Sorunun orijinal sürümü için, yalnızca son komutun PID'si istendiğinde, özel değişken $!mükemmeldir.

foo | bar | baz &
baz_pid=$!

Diğer işlemlerin PID'lerine benzer kolay erişim yoktur.

$pipestatus(Zsh) ve $PIPESTATUS(bash) 'ın eklenmesi uzun sürdü , nihayet bize $?orijinal Bourne kabuğundan beri var olan sonuncunun yanı sıra, bir boru hattındaki tüm çıkış durumlarına erişmemizi sağladı . Belki de $!sonunda benzer bir şey olacaktır .


Listede isteğe bağlı bir komutun PID'sini sormak için soruyu düzenlediğimde sorun olur mu? Yoksa yeni bir soru mu başlatmalıyım?
muru

Buna cevap vermek için muhtemelen çok daha uzun süre beklemeniz gerekecek.

Sorun değil, acil sorun çözüldü, şimdi merak sorumlu. O zaman ben düzenleyeceğim. Sadece kafa karıştırıcı, çünkü soruların büyük ölçüde değiştiğini ve eski cevapların çok yerinde görünmediğini gördüm.
muru

@muru - bunu referans alan yeni bir Q yapmanın daha iyi olacağını unutmayın.
slm

@slm usulüne uygun şekilde not edildi. Gelecekte yapacak.
muru

4

Sanırım burada önerildiği gibi bir şeyler yapabilirsin .

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

Yukarıdaki örnekte, üçüncü borulu işlemin pidini aldım ve dosya pidine not ettim. Herhangi bir borulu işlem için not olabilir.


İlginç, ancak bu komutlar dizisini değiştirmeyi gerektiriyor. Komutlar yürütüldükten sonra fazla kullanılmaz.
muru

@muru - ne? herhangi bir PID yürütmeyi bitirdikten sonra ne işe yarar? boru hattının PID'sini istiyor musunuz? jobs -p. ile işaret SIGPIPE. İstiyor musun cmdi- bu.
mikeserv

1
@mikeserv Arka plandalarsa, konuştuğumuz gibi çalışıyorlar. Bunun için komut satırını hangi sihirbazla değiştirmem gerekiyor?
muru

1
Bu bir büyücülük olurdu. bir hata ayıklayıcıya ihtiyacınız var.
mikeserv

Bunu, arka plan süreçlerini başlatmak, bir duruma ulaşmasını beklemek ve sonra öldürmek için yararlı bir model olarak görüyorum. Herhangi birinin ilgilenmesi durumunda: gist.github.com/MatrixManAtYrService/…
MatrixManAtYrService

2

Taşınabilir olmayan, Linux'a özgü bir çözüm, süreçleri birbirine bağlayan boruları kullanarak izlemek olabilir. Boru hattındaki ilk ( jobs -p) ve last ( $!) komutlarının PID'lerini alabiliriz . Her iki PID'yi kullanarak, bu komut dosyası işi yapabilir:

#! /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

Meraklı olmak için, burada bu tür şeyler hakkında daha fazla bilgi var: unix.stackexchange.com/a/486233/146169
MatrixManAtYrService

0

Bu kodda sıfır tabanlı diziler kullanıyorum. Sadece koştuğun şeye dikkat et eval.

#!/bin/bash

cmd=('sleep 10' 'sleep 2' 'sleep 5')
first=1
for c in "${cmd[@]}"; do
  ((first)) && { pipe=$c; first=0; } || pipe+='|'$c
done
shopt -u lastpipe
eval $pipe &

printf 'Pipe:\n%s\n\n' "$pipe"

shellpid=$BASHPID
parent=$(ps -o pid= --ppid $shellpid | head -n -1)
declare -a pids=()
mapfile -t pids < <(printf '%s\n' $(ps -o pid= --ppid $parent))
printf '%s\n' 'Listing the arrays:'
printf '%2s %6s %s\n' i PID command
for i in "${!cmd[@]}"; do
    printf '%2d %6d %s\n' "$i" "${pids[i]}" "${cmd[i]}"
done

printf '\n%s\n' 'ps listing:'
ps xao pid,ppid,command | head -n 1
ps xao pid,ppid,command | tail | head -n -3
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.