Kıvırcık parantez ile Bash alt kabuk oluşturma


31

Göre , bu , çengelli parantez komutları listesini yerleştirilmesi geçerli kabuk bağlamında yürütülecek listesini neden olur. Alt kabuk oluşturulmaz .

psBunu çalışırken görmek için kullanma

Bu, doğrudan komut satırında yürütülen bir işlem hattı için işlem hiyerarşisidir. 4398, giriş kabuğu için PID'dir:

sleep 2 | ps -H;
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29696 pts/23   00:00:00   sleep
   29697 pts/23   00:00:00   ps

Şimdi doğrudan komut satırında yürütülen küme parantezleri arasındaki bir işlem hattı için işlem hiyerarşisini izler. 4398, giriş kabuğu için PID'dir. Her şeyin mevcut kabuk bağlamında yürütüldüğünü kanıtlayan yukarıdaki hiyerarşiye benzer :

{ sleep 2 | ps -H; }
   PID TTY          TIME CMD
    4398 pts/23   00:00:00 bash
    29588 pts/23   00:00:00   sleep
    29589 pts/23   00:00:00   ps

Şimdi, bu, sleepboru hattının içinde kendisinin küme parantezlerinin içine yerleştirildiği süreç hiyerarşisidir (yani, her iki telin iki seviyesi)

{ { sleep 2; } | ps -H; }
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29869 pts/23   00:00:00   bash
   29871 pts/23   00:00:00     sleep
   29870 pts/23   00:00:00   ps

Belgeler, kıvrımlı parantezler arasında komutların geçerli kabuk bağlamında yürütüldüğünü belirtirken neden 3. durumda bashçalıştırılacak bir alt kabuk oluşturmak zorunda sleep?


İlginçtir, çünkü üçüncü durumda, iç grup boru hattının bir parçası olduğundan ve bu nedenle, örneğin, boru hattının bir parçası olan diğer herhangi bir fonksiyon çağrısında olduğu gibi alt kabukta yürütüldüğü için tahmin ediyorum. Mantıklı geliyor?
Miroslav Koškár

2
"Shell gerekir" öyle diye ... Boru hatları vardır söyleyemem değil kabuk bağlamında yürütülen. Boru hattı harici komutlardan başka bir şey içermiyorsa, alt işlemler oluşturmak yeterlidir. { sleep 2 | command ps -H; }
Hauke ​​Laging

Yanıtlar:


26

Bir boru hattında, tüm komutlar aynı anda (farklı stdout / stdin borularıyla bağlı olarak) farklı işlemlerde çalışır.

İçinde

cmd1 | cmd2 | cmd3

Her üç komut da farklı işlemlerde çalışır, bu yüzden en az iki tanesinin bir çocuk işleminde çalışması gerekir. Bazı mermiler bunlardan birini geçerli kabuk işleminde çalıştırır (eğer yerleşikse readveya boru hattı komut dosyasının son komutuysa), ancak bashhepsini kendi ayrı işlemlerinde çalıştırır ( lastpipeson bashsürümlerdeki seçenek ve belirli koşullar altında ).

{...}grup komutları. Bu grup bir boru hattının parçasıysa, basit bir komut gibi ayrı bir işlemde çalışması gerekir.

İçinde:

{ a; b "$?"; } | c

Bunun a; b "$?"ayrı bir süreç olduğunu değerlendirmek için bir kabuğa ihtiyacımız var, bu yüzden bir denizaltıya ihtiyacımız var. Kabuk b, bu grupta çalıştırılacak en son komut olduğu için çatallama yapmadan optimizasyon yapabilir . Bazı mermiler yapar ama görünüşe göre değil bash.


Her üç komut da farklı işlemlerde çalışıyor, bu yüzden en az ikisinin bir deniz kabuğu altında çalışması gerekiyor . ” Bu durumda neden bir deniz kabuğu gerekir? Ana kabuk ağaç işlemlerine neden olmaz mı? Veya, " bir deniz kabuğu altında koşmak zorunda" derken, kabuğun kendisini tutacağını mı ve sonra her cmd1 cmd2 ve cmd3'ü çalıştırdığını mı kastediyorsunuz? Eğer bunu uygularsam, bash -c "sleep 112345 | cat | cat "sadece bir bash yarattığımı ve sonra diğer serpiştirici alt basamağa sahip olmayan 3 çocuğu görüyorum.
Hakan Baba

" A; b" $? "Nın ayrı bir işlem olduğunu değerlendirmek için bir kabuğa ihtiyacımız var, bu yüzden bir alt kabuğa ihtiyacımız var. " Nedenini de genişletebilir misiniz? Bunu anlamak için neden bir alt çarka ihtiyacımız var? Bunu anlamak için ne gerekiyor? Ayrıştırmanın gerekli olduğunu sanıyorum ama başka ne var? . Ana kabuk ayrıştırılamaz a; b "$?"mı? Gerçekten bir alt tekerlek için temel bir ihtiyaç var mı, yoksa bash konusunda bir tasarım kararı / uygulaması olabilir mi?
Hakan Baba

@HakanBaba, potansiyel karışıklığı önlemek için bunu "çocuk süreci" olarak değiştirdim.
Stéphane Chazelas

1
@HakanBaba, ayrıştırma ebeveynde yapılır (kodu okuyan işlem, tercümanı o kodun geçmediği sürece çalıştıran eval), ancak değerlendirme (ilk komutu çalıştır, bekle, ikinciyi çalıştır) boruya bağlı stdout olan çocukta yapılır.
Stéphane Chazelas

içinde { sleep 2 | ps -H; }ana Bash gören sleep 2bir çatal / exec gerektirir. Fakat { { sleep 2; } | ps -H; }ana bashta { sleep 2; }başka bir deyişle bazı bash kodu görülür. Ebeveyn çatal / exec'i kaldırabilir gibi görünüyor, sleep 2ancak karşılaşılan bash kodunu işlemek için yinelemeli olarak yeni bir bash ortaya koyuyor. Bu benim anlayışım, mantıklı mı?
Hakan Baba

19

Kıvrımlı parantezlerin yuvalanması, çağrılması için yeni bir alt kabuk gerektiren ilave bir kapsam seviyesi oluşturduğunuzu gösteriyor gibi görünmektedir. Bu efekti ps -Hçıktılarınızdaki Bash'in 2. kopyası ile görebilirsiniz .

Yalnızca ilk küme parantezinde belirtilen işlemler orijinal Bash kabuğunun kapsamında gerçekleştirilir. İç içe geçmiş tüm küme parantezleri, kendi kapsamındaki Bash kabuğunda çalışacaktır.

Örnek

$ { { { sleep 20; } | sleep 20; } | ps -H; }
  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5012 pts/1    00:00:00   bash
 5014 pts/1    00:00:00     bash
 5016 pts/1    00:00:00       sleep
 5015 pts/1    00:00:00     sleep
 5013 pts/1    00:00:00   ps

Karışımdan | ps -Hçıktıktan sonra iç içe geçmiş küme parantezlerini görebiliriz ps auxf | less, başka bir kabukta koşabiliriz .

saml     29190  0.0  0.0 117056  3004 pts/1    Ss   13:39   0:00  \_ bash
saml      5191  0.0  0.0 117056  2336 pts/1    S+   14:42   0:00  |   \_ bash
saml      5193  0.0  0.0 107892   512 pts/1    S+   14:42   0:00  |   |   \_ sleep 20
saml      5192  0.0  0.0 107892   508 pts/1    S+   14:42   0:00  |   \_ sleep 20
saml      5068  0.2  0.0 116824  3416 pts/6    Ss   14:42   0:00  \_ bash
saml      5195  0.0  0.0 115020  1272 pts/6    R+   14:42   0:00      \_ ps auxf
saml      5196  0.0  0.0 110244   880 pts/6    S+   14:42   0:00      \_ less

Ama bekleyin dahası var!

Yine de boruları çıkarır ve bu emir biçimini kullanırsanız, gerçekte ne beklediğinizi görürüz:

$ { { { sleep 10; } ; { sleep 10; } ; sleep 10; } } | watch "ps -H"

Şimdi ortaya çıkan izleme penceresinde, olan biten her 2 saniyede bir güncelleme alıyoruz:

İşte ilki sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5678 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5681 pts/1    00:00:00     watch
 5682 pts/1    00:00:00       ps

İşte ikinci sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5691 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5694 pts/1    00:00:00     watch
 5695 pts/1    00:00:00       ps

İşte üçüncü sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5704 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5710 pts/1    00:00:00     watch
 5711 pts/1    00:00:00       ps

Her üç uykunun farklı yuva seviyelerinde kıvrılmış parantezlerde çalıştırıldığına dikkat edin, Bash'in PID 5676'sında etkili bir şekilde kalındığı söylenebilir. Bu nedenle, sorununuzun kullanımı ile özdeşleşmiş olduğuna inanıyorum | ps -H.

Sonuçlar

Kullanımı | ps -H(yani boru) neler olduğunu sorgulamak çalışırken böylece yöntemi kullanmayan, ek bir alt kabuk neden oluyor.


bu nedenle, "İlk küme parantezleri içerisinde belirtilen işlemler, orijinal Bash kabuğunun kapsamı içerisinde gerçekleştirilir."
Xealits

@ xealits - Bana sorduğun bir takip Q mu?
slm

@slm, sadece gördüğüm gibi, cevabın ana noktasına yapılan vurgu. Kıvrımlı parantezlerin birinci seviyesindeki komutlar geçerli kabukta çalıştırılır, iç içe geçmiş parantezler yeni kabuklar yaratır. Parantezler, birinci seviyede hemen alt kabuk oluşturmada farklılık gösterir. Yanlış anladıysam - düzelt beni. Ancak, diğerlerinin işaret ettiği gibi, ilk sorunun boru hatları da var. Böylece ayrı işlemlerin oluşturulması. Kıvrımlı kaşlı ayraçlar ayrı bir işlem için kullanıldığında bir kabuk oluşturmak zorundadır. Dolayısıyla, muhtemelen, söz konusu davranışın nedeni budur.
xealits

Şimdi, gönderinizi yeniden okuduktan sonra, hatalı olduğumu görüyorum - nesting deyimi yalnızca boru hatları olan durumla ilgilidir. Öyleyse, küme parantezleri, onlarla ayrı bir işlem yapmadığınız sürece yeni kabuklar oluşturmaz - o zaman mecburdurlar.
xealits

@ xealits - bu doğru.
slm

7

Testlerimin sonuçlarını yayınlayacağım, bu da bash'ın bir grup komutu için bir alt kabuk oluşturduğuna ve sadece boru hattının bir parçasıysa, ki bu da denilen bir fonksiyonu çağırmak gibi bir şeye benzer olduğunu gösteriyor. alt kabukta.

$ { A=1; { A=2; sleep 2; } ; echo $A; }
2

$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
1

Benim A da bunu gösteriyor.
slm
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.