Bir kabuk komut dosyası ile başladığında #!
, bu ilk satır kabuk söz konusu olduğunda bir açıklamadır. Ancak ilk iki karakter sistemin başka bir kısmı için anlamlıdır: çekirdek. İki karaktere shebang#!
denir . Mesele rolünü anlamak için bir programın nasıl yürütüldüğünü anlamanız gerekir.
Bir programın bir dosyadan yürütülmesi, çekirdeğin eylemini gerektirir. Bu execve
sistem çağrısının bir parçası olarak yapılır . Çekirdeğin dosya izinlerini doğrulaması, şu anda çağıran işlemde çalıştırılabilir yürütülebilir dosyayla ilişkili kaynakları (bellek, vb.) Boşaltması, yeni yürütülebilir dosya için kaynak ayırması ve denetimi yeni programa aktarması (ve Bahsetmeyeceğim). execve
Sistem çağrısı anda çalışan işlemin kodu yerine geçer; fork
yeni bir işlem oluşturmak için ayrı bir sistem çağrısı var .
Bunu yapmak için, çekirdek yürütülebilir dosyanın biçimini desteklemelidir. Bu dosya, çekirdeğin anlayacağı şekilde düzenlenmiş makine kodu içermelidir. Kabuk betiği makine kodu içermediğinden, bu şekilde yürütülemez.
Mesele mekanizması, çekirdeğin kodu başka bir programa yorumlama görevini ertelemesini sağlar. Çekirdek yürütülebilir dosyanın başladığını gördüğünde #!
, sonraki birkaç karakteri okur ve dosyanın ilk satırını (ön #!
ve isteğe bağlı boşluk eksi ) başka bir dosyanın yolu (artı burada tartışmayacağım argümanlar) olarak yorumlar. ). Çekirdeğin dosyayı yürütmesi söylendiğinde ve dosyanın /my/script
satırla başladığını gördüğünde #!/some/interpreter
, çekirdek /some/interpreter
argümanla yürütülür /my/script
. Ardından , yürütmesi gereken bir komut dosyası olduğuna /some/interpreter
karar vermek /my/script
gerekir.
Dosyalardan hiçbiri çekirdeğin anlayabileceği bir formatta yerel kod içermiyorsa ve bir shebang ile başlamıyorsa ne olur? Peki, dosya çalıştırılamaz ve execve
sistem çağrısı hata koduyla başarısız olur ENOEXEC
(Yürütülebilir format hatası).
Bu hikayenin sonu olabilir, ancak çoğu mermi bir geri dönüş özelliği uygular. Çekirdek geri dönerse ENOEXEC
, kabuk dosyanın içeriğine bakar ve bir kabuk betiği gibi olup olmadığını kontrol eder. Kabuk, dosyanın bir kabuk betiği gibi göründüğünü düşünürse, dosyayı tek başına yürütür. Bunun nasıl yapıldığına dair ayrıntılar kabuğa bağlıdır. ps $$
Senaryonuza ekleyerek neler olduğunu ve daha fazlasını strace -p1234 -f -eprocess
1234'ün kabuğun PID'si olduğu işlemi izleyerek görebilirsiniz .
Bash'da, bu geri dönüş mekanizması çağrılarak uygulanır, fork
ancak uygulanmaz execve
. Çocuk bash işlemi kendi iç durumunu temizler ve çalıştırmak için yeni komut dosyasını açar. Bu nedenle, komut dosyasını çalıştıran işlem hala orijinal bash kodu görüntüsünü ve bash'ı özgün olarak çağırdığınızda iletilen orijinal komut satırı bağımsız değişkenlerini kullanıyor demektir. ATT ksh da aynı şekilde davranır.
% bash --norc
bash-4.3$ ./foo.sh
PID TTY STAT TIME COMMAND
21913 pts/2 S+ 0:00 bash --norc
Aksine Dash, argüman olarak iletilen komut dosyasının yolunu ENOEXEC
arayarak tepki verir /bin/sh
. Başka bir deyişle, kısa çizgiden bir shebangless komut dosyası yürüttüğünüzde, komut dosyasının bir shebang satırı varmış gibi davranır #!/bin/sh
. Mksh ve zsh aynı şekilde davranırlar.
% dash
$ ./foo.sh
PID TTY STAT TIME COMMAND
21427 pts/2 S+ 0:00 /bin/sh ./foo.sh