Yeni başlayan sürecin parasını nasıl alabilirim


70

Süreci başlatmak (örn. MyCommand) ve onun parasını almak istiyorum (daha sonra öldürmek için).

PS ve süzgeç adına göre denedim, ancak işlemi adlara göre ayırt edemiyorum

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

Çünkü süreç isimleri benzersiz değildir.

İşlemi şu şekilde yapabilirim:

myCommand &

Bu PID’yi aşağıdaki adresten alabileceğimi öğrendim:

echo $!

Daha basit bir çözüm var mı?

MyCommand'ı çalıştırmaktan ve PID'sini bir satır komutunun sonucu olarak almaktan memnuniyet duyarım.

Yanıtlar:


77

Bundan daha basit ne olabilir echo $!? Bir satır olarak:

myCommand & echo $!

Bu komutları "&" ile birleştirdiğiniz için teşekkür ederim, bana çok yardımcı oldu.
rafalmag

8
bir bash betiğinde, programları başlatan bir döngüde, $! doğru değil. Bazen betiğin kendisinin, bazen bu senaryoda yeni başlatılan sürecin besini elde etmek için herhangi bir çözümden oluşan grep veya awk komutunu döndürür? pid gibi bir şey = myprogramharika olurdu

2
Bu komutun &önceki satırı olduğu gibi bir komut kullanarak başlatılmasını gerektiriyorsa , aksi halde eko temel olarak boş döner.
rogerdpack

2
Gibi değişken değişkenine atama command & echo $!, bu adımda yürütmeyi dondurur :(
Shashank Vivek 9

26

Komutu küçük bir komut dosyasına sarın

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file

20

Sen kullanabilirsiniz sh -cve exechatta komutunun PıD'YI almak için önce o çalışır.

Başlamak için myCommand, PID'i çalışmaya başlamadan önce yazdırılacak şekilde kullanabilirsiniz:

sh -c 'echo $$; exec myCommand'

Nasıl çalışır:

Bu, yeni bir kabuk başlatır, bu kabuğun PID'sini yazdırır ve daha sonra aynı PID'ye sahip olmasını sağlayarak kabuğunu komutunuzla değiştirmek için execyerleşimi kullanır . Kabuğunuz yerleşik bir komutu çalıştırdığında, kabuğunuz aslında kendi ayrı PID'sine sahip olan ve daha sonra komut haline gelen yeni bir kopyasını oluşturma davranışından ziyade, bu komut haline geliyor .exec

Bunu asenkron yürütme (ile &), iş kontrolü veya aramayı içeren alternatiflerden çok daha basit buluyorum ps. Bu yaklaşımlar gayet iyi, ancak onları kullanmak için belirli bir nedeniniz olmadığı sürece - örneğin, belki de komut zaten çalışıyor, bu durumda PID'sini aramak veya iş kontrolünü kullanmak mantıklı olacaktır - önce bu yolu düşünmenizi öneririm. (Ve bunu başarmak için kesinlikle karmaşık bir senaryo veya başka bir program yazmayı düşünmeyeceğim).

Bu cevap , bu tekniğin bir örneğini içerir.


Bu komutun bölümleri zaman zaman ihmal edilebilir, ancak genellikle değil.

Kullandığınız kabuk bir Bourne stili olsa ve dolayısıyla execbu semantik ile yerleşik yapıyı desteklese bile , genellikle bu amaç için sh -cyeni, ayrı bir kabuk işlemi oluşturmaktan kaçının (veya eşdeğeri) kullanmaktan kaçınmamalısınız.

  • Kabuk bir kez olunca myCommand, sonraki komutları çalıştırmak için bekleyen bir kabuk yoktur. Kendisini değiştirdikten sonra sh -c 'echo $$; exec myCommand; fookaçmayı deneyemezdi . Bunu en son komut olarak çalıştıran bir komut dosyası yazmıyorsanız, yalnızca diğer komutları çalıştırdığınız bir kabukta kullanamazsınız .foomyCommandecho $$; exec myCommand
  • Bunun için alt kabuk kullanamazsınız . (echo $$; exec myCommand)sözdizimsel olarak daha güzel olabilir sh -c 'echo $$; exec myCommand', ancak $$içeri ( )girdiğinizde, alt kabuğun kendisinden değil, üst kabuğun PID değerini verir. Ancak, yeni komutun PID'i olacak olan deniz kabuğunun PID'sidir. Bazı kabukları Eğer altkabuk en PID, bulmak için kendi taşınabilir olmayan mekanizmalar getirmesi olabilir bunun için kullanın. Özellikle, Bash 4'te , (echo $BASHPID; exec myCommand)çalışır.

Son olarak, bazı mermilerin, daha sonra bir şey yapmak zorunda kalmayacakları biliniyorsa (örneğin, ilk önce forgo bıraktıkları gibi) bir komutu çalıştırdıkları bir optimizasyon yapacağını unutmayın exec. Bazı mermiler, çalıştırılacak en son komut olduğu zaman bunu yapmaya çalışır, bazıları ise sadece komuttan önce veya sonra başka bir komut olmadığında ve diğerleri de bunu yapmaz. Bunun etkisi, eğer yazmayı execve kullanmayı unutursanız sh -c 'echo $$; myCommand', bazen bazı kabukları olan bazı sistemlerde size doğru PID'yi vermesidir. Bu tür davranışlara güvenmeyi ve bunun yerine her zaman ihtiyaç duyduğunuz şeyi dahil etmeyi öneririm .exec


Koşmadan önce myCommand, bash betiğimde bir dizi çevre değişkeni ayarlamam gerekiyor. Bunlar execkomutun çalıştığı ortama mı geçecek?
kullanıcı5359531

Ortamım execkomuta geçiyor gibi görünüyor . Bununla birlikte, bu yaklaşım, birlikte çalışmanız gereken myCommanddiğer işlemlere başladığında işe yaramaz; Bu şekilde bir kill -INT <pid>nereden pidelde edildiğimi belirttiğim zaman , sinyal başlatılan alt işlemlere ulaşmaz myCommand, oysa myCommand şu anki seansta ve Ctrl + C'de çalışırsam sinyaller doğru şekilde yayılır.
kullanıcı5359531

1
Bunu denedim, ancak myCommand işleminin pid'i, echo $$ +1 tarafından verilen pid çıkışı gibi görünüyor. Yanlış bir şey mi yapıyorum?
crober

sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
Komutum

7

Daha basit bir çözüm bilmiyorum ama $ kullanmıyor! yeterince iyi? Başkaları tarafından söylendiği gibi, daha sonra ihtiyacınız olursa, değeri her zaman başka bir değişkene atayabilirsiniz.

Yan nota olarak, ps'den boru almak yerine pgrepveya kullanabilirsiniz pidof.


5

pid'i bir dosyaya kaydettikten sonra exec bash betiğinden:

örnek:

Diyelim ki "forever.sh" adında bir betiğiniz var, pgs, p2, p3

forever.sh kaynak kodu:

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "$0 running with parameters \"$@\""
    sleep 5
done

bir reaper.sh oluşturun:

#!/bin/sh

echo $$ > /var/run/$1.pid
exec "$@"

sonsuza kadar koşmak reaper.sh aracılığıyla:

./reaper.sh ./forever.sh p1 p2 p3 p4 &

forever.sh, her 5 saniyede bir syslog yazmak için bir satır kaydetmekten başka bir şey yapmaz

şimdi /var/run/forever.sh.pid adresindeki bir iadeniz var

cat /var/run/forever.sh.pid 
5780

ve sonsuza dek .sh çalışıyor. syslog grep:

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"

işlem tablosunda görebilirsiniz:

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4

3
oh ve "oneliner": / bin / sh -c 'eko $$> / tmp / my.pid && exec programı args' &
user237419

1
Argümanlardaki iç boşlukları düzgün bir şekilde korumak için, exec "$@"yerine kullanmalısınız exec $*. Teknik olarak korumanız gereken şey boşluk değil, IFS kabuk parametresindeki karakterlerin oluşmasıdır (varsayılan olarak boşluk, sekme ve yeni satır).
Chris Johnsen

alınan nokta. :)
user237419 25:10

Teşekkür ederim, $$ parametresini bilmiyordum. Çok faydalı olabilir.
rafalmag

3

Beşinci kabukta $!, jobs -pyerleşik bir alternatif olabilir . Bazı durumlarda, !giriş $!, değişken genişlemeden önce (veya bunun yerine) kabuk tarafından yorumlanır, bu da beklenmeyen sonuçlara yol açar.

Bu, örneğin işe yaramaz:

((yourcommand) & echo $! >/var/run/pidfile)

Bu olacak:

((yourcommand) & jobs -p >/var/run/pidfile)

Bence sen ((senin emrin) ve işler -p> / var / run / pidfile) demek istedin.
Dom

1

Gibi bir şey kullanabilirsiniz:

$ myCommand ; pid=$!

Veya

$ myCommand && pid=$!

İki komut ;veya kullanarak eklem olabilir &&. İkinci durumda, teklif sadece ilk komut başarılı olursa verilir. İşlem kimliğini buradan alabilirsiniz $pid.


3
OP PID'yi almak istiyor, böylece daha sonra öldürebilir. ; ve &&, asıl işlemin echo $ 'dan önce çıkmasını gerektirir! Idam edildi.
user9517 24:10

Evet haklısın. Komutum sona erdikten sonra bu size ücreti verecek.
Khaled

6
başvurma $! sonra &&veya ;işlem komut ayırıcı sol tarafı için başlatılan arasında size PID asla vermez. $!yalnızca eşzamansız başlatılan işlemler için ayarlanır (örneğin, genellikle &ancak bazı kabukların başka yöntemleri de vardır).
Chris Johnsen

bu yardımcı olur ve neden kimse oy kullanmadı? olsa iyi iş :)
tapınak

1

Bu bir hack-y cevabı biraz ve çoğu insan için muhtemelen işe yaramaz. Aynı zamanda çok büyük bir güvenlik riski düşüncesizdir, bu yüzden güvende olacağınızdan ve girdilerin sterilize edildiğinden emin olmadığınız sürece yapmayın.

Burada küçük C programını derleyin start(ya da ne istersen) olarak adlandırılan bir ikili dosyada toplayın , sonra da programını çalıştırın../start your-program-here arg0 arg1 arg2 ...

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc >= 2)
    {
        printf("%lu\n", (long unsigned) getpid());
        if (execvp(argv[1], &argv[1]) < 0)
        {
            perror(NULL);
            return 127;
        }
    }
    return 0;
}

Uzun lafın kısası, bu işlem PID’yi yazdırır stdout, ardından programınızı işleme koyar. Yine de aynı PID'ye sahip olmalı.


Bu kodun döndürdüğü PID numarasını bir bash değişkeninde nasıl kaydedebilirim? Bana net olmayan bir sebepten dolayı stdout, bu örnekte kaydedilmiş gibi görünmüyor:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
Tfb9

@ Tfb9: Dürüst olmak gerekirse diğer yaklaşımlardan birini öneriyorum; Bunu 2+ yıl önce yazdım ve bugüne kadar sunulan hackier / hataya açık yöntemlerden biriydi (ya da öyle düşünüyorum).
tonysdg

Not için teşekkürler. Sanırım sleep 10 & PID_IS=$!; echo $PID_IS
bununla
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.