2012-03-13 27 views
9

Oturum lideri olarak bir komut dosyası yürütecek bir sarıcı yazmayı deniyorum. linux komutunun setsid davranışıyla karıştırıldım. Bu komut dosyasını düşünün, test.sh seslendi:linux command setsid

çıkış yerine getirilinceye ya da kaynaklı olup olmadığına göre değişir
#!/bin/bash 
SID=$(ps -p $$ --no-headers -o sid) 
if [ $# -ge 1 -a $$ -ne $SID ] ; then 
    setsid bash test.sh 
    echo pid=$$ ppid=$PPID sid=$SID parent 
else 
    sleep 2 
    echo pid=$$ ppid=$PPID sid=$SID child 
    sleep 2 
fi 

:

$ bash 
$ SID=$(ps -p $$ --no-headers -o sid) 
$ echo pid=$$ ppid=$PPID sid=$SID 
pid=9213 ppid=9104 sid= 9104 
$ ./test.sh 1 ; sleep 5 
pid=9326 ppid=9324 sid= 9326 child 
pid=9324 ppid=9213 sid= 9104 parent 
$ . ./test.sh 1 ; sleep 5 
pid=9213 ppid=9104 sid= 9104 parent 
pid=9336 ppid=1 sid= 9336 child 
$ echo $BASH_VERSION 
4.2.8(1)-release 
$ exit 
exit 

Yani, bana öyle geliyor ki setsid döner derhal komut kaynaklı olduğunda, ancak komut dosyası yürütüldüğünde çocuğunu bekler. Neden kontrol eden bir tty'nin varlığının setsid ile ilgisi var? Teşekkürler!

Düzeltme: Açıklama için ilgili tüm komutlara pid/ppid/sid raporlaması ekledim.

cevap

17

The source code of the setsid utility aslında çok basittir. İşlem kimliğinin ve işlem grubu kimliğinin eşit olduğunu (yani, bir işlem grubunun lideri olduğunu görürse) — ve çocuk işlemi için hiçbir zaman wait() s olduğunu görürse, yalnızca fork() s olduğunu unutmayın. fork() s, daha sonra ana işlem hemen döner. ,fork() değilse, o zaman bir çocuk için wait() ing görünümünü verir, ancak gerçekten ne olur çocuk ve bu Bash, wait() ing (her zaman yaptığı gibi). (Tabii ki, fork() gerçekten yaparsa, Bash, oluşturduğu alt öğe için wait() yapamaz, çünkü çocukları için wait() süreçleri torunlarına değil.)

Yani görüyoruz davranış, farklı bir davranış doğrudan bir sonucudur:

  • Çalıştırmak . ./test.sh veya source ./test.sh veya etajer — ya da bu konuda, sadece doğrudan setsid çalıştırmak Bash komut istemi — Bash, job control için yeni bir işlem grubu kimliğiyle setsid başlatır, bu nedenle setsid, işlem-grubu kimliğiyle aynı işlem kimliğine sahip olur (yani, bir işlem grubu lideridir), böylece fork() ve wait() değil.
  • Eğer ./test.sh veya bash test.sh durumlarda ne çalıştırın ve onun süreç numarası ve süreç grubu kimliği farklı olacaktır bu yüzden kazandı yüzden, setsid, setsid bunu çalışıyor komut dosyasıyla aynı süreç grubunun bir parçası olacak başlattığında fork(), bu yüzden beklemenin görünümünü verir (aslında wait() ing olmadan).
+4

Haklısınız. “Setsid” in fazladan bir bayrak almasını teklif etmeye değip değmeyeceğini merak ediyorum, “-w” demek, eğer varlığı varsa çocuğu için beklemesi gerekir. Olduğu gibi, davranışının tutarsız olduğunu hissediyorum: hemen ve sadece bir grup lideri tarafından çalıştırılırsa geri döner (ve çatal). Artı, dediğin gibi, sadece 'setsid' çocuğunu bekleyebilir, çağıran 'bash' torunu bekleyemez. –

+1

Evet; ve sadece genel olarak, beklemeden 'çatal' için garip bir şey. Kolej İşletim Sistemleri profesörünün onaylayacağını sanmıyorum. :-P – ruakh

1

Gözlemlediğim davranış, sizinkilerden farklı olsa da beklediğim şey. Bir şeyleri doğru gördüğünüzden emin olmak için set -x kullanabilir misiniz?

 
$ ./test.sh 1 
child 
parent 
$ . test.sh 1 
child 
$ uname -r 
3.1.10 
$ echo $BASH_VERSION 
4.2.20(1)-release 

./test.sh 1 çalışan, komut dosyasının ebeveyn - etkileşimli kabuk - yani $$ != $SID seans lideridir ve koşullu doğrudur.

. test.sh 1'u çalıştırırken, etkileşimli kabuk, komut dosyasını işlem sırasında yürütür ve kendi oturum lideridir, bu nedenle $$ == $SID ve koşullu yanlıştır, dolayısıyla hiçbir zaman iç çocuk komut dosyasını yürütmez.

+0

Haklısınız; ama benim endişem, senaryoyu başlatan kabuk (ya yürütme ya da kaynak) başladığında, bir oturum lideridir. Orijinal örneğimde yaptığım gibi başka bir "bash" seviyesi eklemeyi deneyin. (Başarmaya çalıştığım şey, betiği garantili bir oturum lideri olarak çalıştırmaktır. Eğer böyle olduğunu varsayarsam, senaryoyu ilk sırada bulundurmanın bir anlamı yoktur.) –

0

Dosyanızda olduğu gibi herhangi bir sorun görmüyorum.

#!/bin/bash 

    ps -H -o pid,ppid,sid,cmd 

    echo '$$' is $$ 

    SID=`ps -p $$ --no-headers -o sid` 

    if [ $# -ge 1 -a $$ -ne $SID ] ; then 
     setsid bash test.sh 
     echo pid=$$ ppid=$PPID sid=$SID parent 
    else 
     sleep 2 
     echo pid=$$ ppid=$PPID sid=$SID child 
     sleep 2 
    fi 

sizsiniz ilgilendiren durum:

./test.sh 1 

Ve beni bu modifiye komut dosyasını çalıştırmak ve neler olduğunu tam olarak göreceksiniz güven ben neler olup bittiğini görmek için kodunuzda ekstra ifadeleri ekledi. Oturum lideri olmayan kabuk betiği çalıştırırsa, else bloğuna gider. Bir şey mi eksik?

Şimdi ne demek istediğimi görüyorum: Komut dosyanızla birlikte ./test.sh 1'u yaptığınızda, üst öğe, çocuğun tamamlanmasını bekler. çocuk ebeveynleri engeller. Fakat çocuğu arka planda başlatırsanız, ebeveynin çocuktan önce tamamlandığını fark edersiniz. Dolayısıyla, sadece betiğinizde bu değişikliği yapın:

 setsid bash test.sh & 
+1

Bu kod parçasının kullanılmasının sebebi: Daha karmaşık bir betikle birleştirin, ki bu da el ile çalıştırılabilir, ya da el ile kaynaklanabilir ya da bildiğim tüm SGE iş motoru tarafından çalıştırılabilir. İhtiyacım olan şey ebeveynin ve çocuğun bir _consistent_ davranışı. İdeal olarak: _if_ 'setsid' gereklidir (yani, zaten oturum lideri değilim) _then_ Ebeveynin çocuğu beklemesini istiyorum. _if_ kısmı benim örneğimdeki her iki senaryoda da geçerlidir: parent 'PID'! = Parent' SID'. Beni etkileyen şey, komut dosyası oluşturulduğunda _then_ bölümünün beklememesidir: ebeveyn çocuktan önce çıkar. –