Parantezler gerçekten komutu alt kabuklara mı koyuyor?


94

Okuduklarımdan, bir komutu parantez içine almak, bir betiği çalıştırmaya benzer şekilde bir alt kabukta çalıştırmalıdır. Bu doğruysa, eğer x dışa aktarılmazsa x değişkenini nasıl görür?

x=1

(echo $x)Komut satırında çalışan 1 ile sonuçlanır

echo $xBir komut dosyasında çalıştırma , beklendiği gibi hiçbir şeyle sonuçlanmaz

Yanıtlar:


134

Alt kabuk, orijinal kabuk işleminin neredeyse özdeş bir kopyası olarak başlar. Kaputun altında, kabuk forksistem çağrısı 1'i çağırır , kod ve hafızası kopyalanan 2 yeni bir işlem yaratır . Alt kabuk oluşturulduğunda, kendisiyle ebeveyn arasında çok az fark vardır. Özellikle, aynı değişkenlere sahiptirler. $$Özel değişken bile alt kabuklarda aynı değeri korur: orijinal kabuğun işlem kimliğidir. Benzer şekilde $PPID, orijinal kabuğun ebeveyni PID'dir.

Birkaç kabuk, alt kabuktaki birkaç değişkeni değiştirir. Bash BASHPID, alt kabuklarda değişen kabuk işleminin PID'sine ayarlar . Bash, zsh ve mksh $RANDOM, üst ve alt kabukta farklı değerler üretmek için düzenler . Ancak, bunlar gibi yerleşik özel durumlar dışında, tüm değişkenler alt kabuktaki orijinal kabuktaki aynı değere, aynı dışa aktarma durumuna, aynı salt okunur duruma vb. Sahiptir. Tüm işlev tanımları, diğer ad tanımları, kabuk seçenekleri ve diğer ayarlar da miras alınır.

Tarafından oluşturulan bir alt kabuk (…), yaratıcısıyla aynı dosya tanımlayıcılarına sahiptir. Alt kabuk yaratmanın diğer yolları, kullanıcı kodunu çalıştırmadan önce bazı dosya tanımlayıcılarını değiştirir; örneğin, bir borunun sol tarafı, boruya standart bir çıkışla bir alt kabuk 3'te uzanır . Alt kabuk aynı akım dizini, aynı sinyal maskesi vb. İle de başlar. Birkaç istisnadan biri, alt kabukların özel tuzakları devralmamasıdır: yok sayılan sinyaller ( ) alt kabukta yok sayılır, ancak diğer tuzaklar ( SİNYAL ) sıfırlanır varsayılan eyleme 4 .trap '' SIGNALtrap CODE

Dolayısıyla bir alt kabuk, bir komut dosyasını çalıştırmaktan farklıdır. Bir komut dosyası ayrı bir programdır. Bu ayrı program tesadüfen aynı zamanda ebeveyn ile aynı tercüman tarafından yürütülen bir senaryo da olabilir, ancak bu tesadüf, ayrı programa ebeveynin iç verisi hakkında herhangi bir özel görünürlük vermez. Dışa aktarılmayan değişkenler dahili veridir, dolayısıyla alt kabuk komut dosyası için tercüman çalıştırıldığında , bu değişkenleri görmez. Dışa aktarılan değişkenler, yani ortam değişkenleri, yürütülen programlara iletilir.

Böylece:

x=1
(echo $x)

1alt kabuk, onu oluşturan kabuğun bir kopyası olduğu için yazdırır .

x=1
sh -c 'echo $x'

Bir kabuğun bir kabuğun alt işlemi olarak çalıştırılması gerekir, ancak xikinci satırın xikinci satırın ondan daha fazla bağlantısı yoktur .

x=1
perl -le 'print $x'

veya

x=1
python -c 'print x'

1 İstisna, ksh93çatalın optimize edildiği ve yan etkilerinin çoğunun öykündüğü kabuktur.
2 Anlamsal olarak onlar kopyadır. Uygulama açısından bakıldığında çok fazla paylaşım var.
3 Sağ taraf için, kabuğa bağlıdır.
4 Bunu test ederseniz, bunun gibi şeylerin$(trap) orijinal kabuğun tuzaklarını rapor edebileceğini unutmayın . Ayrıca birçok kabuğun, tuzak içeren köşelerde sıkıntılara sahip olduğunu unutmayın. Örneğin, ninjalj , bash 4.3'ten itibaren, “iki alt kabuk” kasasındaki iç içe geçmiş alt kabuktanbash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )' gelen ERRtuzağı çalıştırdığını , ancak ERRara alt kabuktaki tuzağın değil - set -EseçeneğininERRtüm alt kabuklara tuzak takın, ancak ara alt kabuk uzağa optimize edilmiştir ve bu yüzden ERRtuzağını çalıştırmak için orada değildir .


2
@Kusalananda No. ( x=out; (x=in; echo $x))
Gilles

2
@ flow2k Bu, aynı seviyede olan şeyler için genişleme sırasıdır. Ancak, genişlemenin değerlendirmeyle nasıl karıştırıldığını da göz önünde bulundurmanız gerekir. Genişleme, iç içe geçmiş bir yapının değerlendirilmesini gerektirdiğinde, ilk önce iç yapı değerlendirilir. Bu nedenle, örneğin değerlendirmek echo $(x=2; echo $x)için parçanın $(x=2; echo $x)genişletilmesi gerekiyor. Bu komutun değerlendirilmesini gerektirir x=2; echo $x. $xParçayı değerlendirdikten sonra bu değerlendirme sırasında meydana gelen genişleme x=2.
Gilles

2
@ flow2k Parametre genişletme ve komut değiştirme arasında sıra yok. Bu cümlenin, genişletme adımlarını ayırmak için noktalı virgül kullandığını unutmayın; ancak parametre genişletme ve komut değiştirme, aynı noktalı virgülle ayrılmış bir cümlededir (evet, ince). Sıra, parçalardan birinin diğer parçayı etkileyen yan etkiye sahip olması durumunda önemlidir, örneğin ( xayarlanmamış) echo $(echo foo >somefile)${x-$(cat somefile)}veya echo $(echo $x),${x=1}.
Gilles

1
@Gilles; Kafam karıştı. Eğer bir alt kabuk bir betiği çalıştırmaktan farklıysa, o zaman neden şöyle söylenir: Bir kabuk betiğinin çalıştırılması, yeni bir işlem olan bir alt kabuk başlatır. ? Ayrıca, kabuk altı ortamının bir kopyası olarak alt kabuk ortamı yaratılacaktır . Bu nedenle, ./file alt kabuk ortamında çalıştırılacak ve değişken atama ile ayarlanan kabuk parametrelerini miras almalıdır.
11'de 13:13

2
@haccks ABS'deki tanım yaklaşık bir değerdir ve çok iyi değildir. Örnekler iyi, ancak bu sayfanın ilk iki satırı hatalı olduklarından çok fazla basitleştirildi. Bir komut dosyasını başka bir komut dosyasından çalıştırmak, alt kabuk olmayan yeni bir işlem başlatır . SUS'ta tanımlar doğrudur (ancak anlaşılması her zaman çok kolay değildir). ./filebir alt kabukta yürütülmez. Ayrıca bkz. Unix.stackexchange.com/q/261638 ve unix.stackexchange.com/a/157962
Gilles

15

Açıkçası, evet, tüm belgelerin dediği gibi, parantez içine alınmış bir komut alt kabukta çalıştırılmaktadır.

Alt kabuk, ebeveynin tüm değişkenlerinin bir kopyasını devralır. Fark, alt kabukta yaptığınız hiçbir değişikliğin üst öğede yapılmadığıdır.

Ksh man sayfası bunu bash olandan biraz daha net hale getirir:

man ksh:

Parantez içindeki bir komut, dışa aktarılmayan değişkenleri kaldırmadan bir alt kabukta yürütülür.

man bash:

(liste)

liste alt kabuk ortamında yürütülür (bkz. KOMUTANLI YÜRÜTME ORTAMI). Kabuğun ortamını etkileyen değişken atamaları ve yerleşik komutlar, komut tamamlandıktan sonra geçerli olmaz.

KOMUTANLI YÜRÜTME ORTAMI

Kabuk, aşağıdakilerden oluşan bir yürütme ortamına sahiptir: [...] değişken ataması [...] tarafından ayarlanan kabuk parametreleri.
Komut değiştirme, parantezle gruplandırılmış komutlar ve asenkron komutlar, kabuk ortamının bir kopyası olan bir alt kabuk ortamında çağrılır, [...]


3
Bu, When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.maddeyi içeren ile karşılaştırılmalıdır: · shell variables and functions marked for export, along with variables exported for the command, passed in the environment(aynı man bashbölümden), bir echo $xbetiğin neden xdışa aktarılmıyorsa neden hiçbir şey yazdırmadığını açıklar .
Johan E
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.