Zarif bir şekilde soyundan gelen süreçlerin listesini alın


23

İnişe geçen tüm süreçlerin (örneğin çocuklar, büyük çocuklar vb.) Bir listesini almak istiyorum $pid. Bu, karşılaştığım en basit yol.

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"

Tüm azalan işlemlerin tam listesini almak için herhangi bir komut veya daha basit bir yöntem var mı?


Hepsine tek bir hatta ihtiyaç duymanızın bir nedeni var mı? Bu çıktıyla ne yapıyorsun? Bunun bir xy problemi olduğunu hissediyorum ve yanlış soruyu soruyorsunuz.
Ürdün

Biçimi temiz olduğu sürece umurumda değil (yani '\n'sınırlandırılmış ve ' 'sınırlandırılmış umrumda değil ). Pratik kullanım örneği: a) saf mazoşizmden yazdığım bir daemonizer betiği (özellikle, "dur" işlevinin, bu daemonize edilen sürecin doğduğu her hangi bir işlem ağacı ile ilgilenmesi gerektiği); ve b) zaman aşımına uğrayan sürecin oluşturmayı başardığı her şeyi öldürecek bir zaman aşımı komut dosyası.
STenyaK

2
@STenyaK Kullanım durumunuz bana süreç grupları ve olumsuz bir argüman aradığınızı düşündürüyor kill. Bkz. Unix.stackexchange.com/questions/9480/… , unix.stackexchange.com/questions/50555/…
Gilles '

@ Gilles'i kullanarak , öldürmek istediğim kesin alt ağacıyla ps ax -opid,ppid,pgrp,cmdaynı olan birçok işlem olduğunu görüyorum pgrp. (Ayrıca, ben göremiyorum setpgrp: debian kararlı paketlerinde her yerde listelenen programı packages.debian.org/... )
STenyaK

1
Başka bir kullanım durumu: Çok fazla kaynak tüketen, örneğin büyük bir paralel yapı gibi, bütün bir işlem ağacında renice / ionice.
Çita

Yanıtlar:


15

Aşağıdakiler biraz daha basittir ve komut adlarında sayıları yok sayma avantajına sahiptir:

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

Veya Perl ile:

pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'

Parantez içindeki sayıları arıyoruz, böylece örneğin karşımıza geçtiğimizde alt işlemi çocuk olarak vermiyoruz gif2png(3012). Ancak komut adı parantez içinde bir sayı içeriyorsa, tüm bahisler kapalıdır. Metin işleme sadece seni alabilir.

Bu yüzden süreç gruplarının gitmenin yolu olduğunu düşünüyorum. Bir sürecin kendi işlem grubunda yürütülmesini istiyorsanız, 'pgrphack' aracını Debian paketindeki 'daemontools'dan kullanabilirsiniz:

pgrphack my_command args

Veya yine Perl'e dönebilirsin:

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args

Buradaki tek uyarı işlem gruplarının yuva yapmamasıdır, bu nedenle bazı işlemler kendi işlem gruplarını oluşturuyorsa, alt işlemleri artık oluşturduğunuz grupta olmayacaktır.


Alt süreçler isteğe bağlıdır ve süreç gruplarını kendileri kullanabilir veya kullanamaz (hiçbir şey kabul edemem). Ancak cevabınız Linux'ta neyin başarılacağına en yakın olanıdır, o yüzden kabul edeceğim. Teşekkürler.
STenyaK

Bu çok faydalı oldu!
Michal Gallovic

Pstree boruları aynı zamanda iplik kimliklerini de içerecektir, yani bir $ pid'in başlattığı dişlerin kimlikleri.
maxschlepzig

Tekli grep kullanabilirsiniz:pstree -lp | grep -Po "(?<=\()\d+(?=\))"
puchu

7
descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}

O bu modern kabukları üzerinde çalışacak belirterek sadece değer olacaktır ( bash, zsh, fishve hatta ksh 99), ancak o eski kabukları üzerinde değil iş, örneğinksh 88
grochmal

@grochmal, ksh-88'de çalışan çapraz bir çözüm için aşağıdaki cevabımı görün.
maxschlepzig

1

En kısa sürüm de bunun gibi komutlarla doğru bir şekilde ilgilendiğini buldum pop3d:

pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'

Eğer gibi garip isimlere sahip komutlar varsa bu yanlış fırsatlar: my(23)prog.


1
Bu, bazı iş parçacığı çalıştıran komutlar için işe yaramaz (çünkü pstree de bu kimlikleri basar).
maxschlepzig

@ maxschlepzig Konu ffmpegkullanmakta çok zor olduğunu fark ettim . Her ne kadar hızlı gözlemlerden, ipliklere kaşlı ayraçlar içinde isimleri verilmiş gibi görünüyor { }.
Çingene Spellweaver

1

Ayrıca doğruluk sorunu var. Nadiren çıktısının ayrıştırılması pstreeçeşitli nedenlerle sorunludur:

  • pstree, PID'leri ve iş parçacığı kimliklerini (isimler küme parantezleri içinde gösterilir) gösterir.
  • komut adı küme parantezleri, parantez içindeki sayıları güvenilir bir şekilde ayrıştırmayı imkansız kılan

Python'unuz ve psutilkurulu paketiniz varsa, tüm soyundan işlemleri listelemek için bu pasajı kullanabilirsiniz:

pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
  print(c.pid)"

(Psutil paketi, örneğin tracerFedora / CentOS'ta mevcut olan komutun bir bağımlılığı olarak kurulur .)

Alternatif olarak, bir bourne kabuğundaki işlem ağacının enine birinci geçişini yapabilirsiniz:

ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
  done | tail -n +2 | tr " " "\n"

Bir çukurun geçişli kapatılmasının hesaplanması için kuyruk kısmı atlanabilir.

Yukarıdakilerin özyinelemeyi kullanmadığını ve ksh-88 ile çalıştığını unutmayın.

Linux'ta, biri pgrepçağrıyı ortadan kaldırabilir ve bunun yerine bilgileri okuyabilir /proc:

ps=2235; while [ "$ps" ]; do echo $ps ; \
  ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
  | tr " " "\n"' | tail -n +2

Bu daha verimlidir, çünkü her PID için bir çatal / yürütme tasarrufu yaparız ve pgrepher aramada bazı ek işler yaparız .


1

Bu Linux sürümü sadece / proc ve ps gerektirir. @ Maxschlepzig'in mükemmel cevabının son parçasından uyarlanmıştır . Bu sürüm, bir döngü içinde bir alt işlem oluşturmak yerine doğrudan kabuktan okur / okur. Bu konu başlığı gibi biraz daha hızlı ve tartışmalı biraz daha zarif.

#!/bin/dash

# Print all descendant pids of process pid $1
# adapted from /unix//a/339071

ps=${1:-1}
while [ "$ps" ]; do
  echo $ps
  unset ps1 ps2
  for p in $ps; do
    read ps2 < /proc/$p/task/$p/children 2>/dev/null
    ps1="$ps1 $ps2"
  done
  ps=$ps1
done | tr " " "\n" | tail -n +2

0

İkinizin (görünüşte çok yapay) her birinin kullanımında, neden bazı talihsiz süreçlerin alt süreçlerini öldürmek istiyorsunuz? Çocuklarının yaşaması veya ölmesi gereken bir süreçten daha iyi ne biliyorsunuz? Bu bana kötü tasarım gibi görünüyor; Bir süreç kendisinden sonra temizlenmelidir.

Eğer gerçekten daha iyisini biliyorsanız, o zaman bu alt süreçleri unutmuş olmalısınız ve 'daemonized süreç' görünüşte güvenilemeyecek kadar aptaldır fork(2).

Alt süreçlerin listesini tutmaktan ya da süreç ağacından gizlice çıkmaktan kaçınmalısınız, örneğin alt süreçleri @Gilles tarafından önerilen şekilde ayrı bir süreç grubuna koyarak.

Her halükarda, daemonize edilmiş sürecinizin, bir işçi temizliği havuzu oluşturmaktan (bununla birlikte içerdiği süreçle birlikte ölmek zorundadır) oluşturmadan daha iyi bir yerde olacağından şüpheleniyorum. .


2
Her iki kullanım durumu da sürekli bir entegrasyon / test ortamında kullanılır, bu yüzden çocuk süreçlerinde mevcut olan bir hata olasılığını ele almaları gerekir. Bu hata, kendilerini veya çocuklarını gerektiği gibi kapatmama durumu olarak kendini gösterebilir, bu yüzden hepsini en kötü durumda kapatabileceğimden emin olmak için bir yola ihtiyacım var .
STenyaK

1
Bu durumda, @Gilles ve @Jander ile birlikteyim; süreç grupları en iyi yoldur.
AnotherSmellyGeek

0

İşte pgrep kullanmanıza ve tüm torunları aynı anda almanıza izin veren bir pgrep sarmalayıcı komut dosyası.

~/bin/pgrep_wrapper:

#!/bin/bash

# the delimiter argument must be the first arg, otherwise it is ignored
delim=$'\n'
if [ "$1" == "-d" ]; then
    delim=$2
    shift 2
fi

pids=
newpids=$(pgrep "$@")
status=$?
if [ $status -ne 0 ]; then
    exit $status
fi

while [ "$pids" != "$newpids" ]; do
    pids=$newpids
    newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
done
if [ "$delim" != $'\n' ]; then
    first=1
    for pid in $pids; do
        if [ $first -ne 1 ]; then
            echo -n "$delim"
        else
            first=0
        fi  
        echo -n "$pid"
    done
else
    echo "$pids"
fi

pgrep_recursive -U $USER javaGeçerli kullanıcıdan gelen tüm Java işlemlerini ve alt işlemlerini bulmak gibi normal pgrep'i çağırdığınız gibi kullanın.


1
Bu bash olduğundan, PID'leri sınırlayıcıya IFS"${array[*]}
eklemek
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.