Hangi kabuk yorumlayıcısı hiç betiği olmayan bir senaryo çalıştırır?


17

Hesabım için varsayılan kabuğun zsh olduğunu varsayalım, ancak terminali açtım ve prac002.shbash'yi çalıştırdım ve komut dosyasını, zsh veya bash'ı çalıştırmak için hangi kabuk yorumlayıcısını kullanacağım? Aşağıdaki örneği düşünün:

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf: 
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)

papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh 
Enter username : Rex
Rex
# Which interpreter did it just use?

** DÜZENLEME: ** İşte betiğin içeriği

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh 
read -p "Enter username : " uname
echo $uname

Senaryo üstte ne diyor?
Michael Homer

@MichaelHomer: Hiçbir şey. Komut dosyasının içeriğini eklemek için soruyu yeni düzenledim. Komut dosyasının yürütülebilir izni var.
7_R3X

Geçerli kabuğu kullanmak istiyorsanız . prac002.sh, komut dosyanızın geçerli dizinde olduğu varsayılarak , olduğu gibi nokta kaynağı yapın.
thecarpy

1
Çalıştır . ./prac002.shve geçerli kabuk, yani nokta ( .), boşluk () ve ardından komut dosyanızın yolu ile çalışır. Komut dosyanızı nokta kaynak olarak adlandırır. ;-)
thecarpy

Yanıtlar:


19

Senaryo #!hangi tercümanın kullanılacağını belirten bir satır satırıyla başlamadığı için POSIX şunları söylüyor :

Eğer execl()fonksiyon POSIX.1-2008 Sistemi Arayüz hacim tanımlanan [ENOEXEC] hataya hata eşdeğer nedeniyle başarısız kabuk ilk olarak arama kaynaklanan yol adı ile çağrılan bir kabuğu olan bir komut eşdeğer yürütür yeni kabuktaki "$ 0" değerinin komut adına ayarlanabilmesi dışında, yeni kabukta kalan argümanlarla birlikte işlenen . Yürütülebilir dosya bir metin dosyası değilse, kabuk bu komut yürütmesini atlayabilir. Bu durumda, bir hata mesajı yazacak ve 126 çıkış durumunu döndürecektir.

Bu ifade biraz belirsizdir ve farklı mermilerin farklı yorumları vardır.

Bu durumda, Bash komut dosyasını kendisini kullanarak çalıştıracaktır . Öte yandan, bunun yerine zsh'den çalıştırırsanız, zshsh (sisteminizde ne olursa olsun) kullanır.

Komut dosyasına şu satırları ekleyerek bu durum için bu davranışı doğrulayabilirsiniz:

echo $BASH_VERSION
echo $ZSH_VERSION

Bash'ten ilk satırın sürümünüzü çıkardığını, ikincisinin ise hangi kabuğu kullanırsanız kullanın hiçbir şey söylemediğini göreceksiniz.

  • Eğer /bin/shdeyişle, diyelim ki, dash, senaryo zsh veya çizgi yürütüldüğünde daha sonra hiçbiri satır çıktısı şey.
  • Eğer /bin/shBash'e bir bağlantınız varsa, her durumda ilk satır çıktısını görürsünüz.
  • Bash'in doğrudan kullandığınızdan farklı bir sürümü varsa /bin/sh, komut dosyasını doğrudan bash'tan ve zsh'den çalıştırdığınızda farklı çıktı görürsünüz.

ps -p $$Rools cevabı gelen komut da kabuk komut dosyası çalıştırmak için kullanılan komutun ilgili faydalı bilgiler gösterecektir.


Bununla birlikte, herhangi bir shebang belirtilmezse, varsayılan kabuk ne olursa olsun VARSAYILAN SHELL kullanır. Bu yüzden her zaman bir imha belirtmelisiniz.
thecarpy

4
Bu, aslında cevabın bütün noktasıydı. İkinci cümleniz kesinlikle doğrudur.
Michael Homer

haklısın, bash kendisini kullanarak çalışır, kutularımın çoğunda varsayılan kabuk olur .... bash, oradan karışıklığım. Ben sadece varsayılan kabuk olarak ksh ile Solaris 8 üzerinde test ettim, yeterince, bash bash olarak çalıştırıyor ... bugün yeni bir şey öğrendim, teşekkürler (upvoted!) ;-)
thecarpy

Teşekkürler. execl()Kabuk betiği bir shebang içermediğinde ve olarak yürütüldüğünde çağrı başarısızlığı olur scriptnamemu? Bir kabuk komut dosyası olarak yürütüldüğünde gerçekleşmez bash scriptnamemi? Bir kabuk betiği bir shebang içerdiğinde ve olarak yürütüldüğünde gerçekleşmez scriptnamemi?
Herkes için


7

Dosya, sistem tarafından tanınan yürütülebilir dosya türlerinden biri olmadığından ve bu dosyayı yürütme izniniz olduğunu varsayarsak, execve()sistem çağrısı genellikle ENOEXEC( yürütülebilir değil ) hatasıyla başarısız olur .

O zaman ne olacak komutu çalıştırmak için kullanılan uygulama ve / veya kütüphane fonksiyonudur.

Bu bir kabuk, execlp()/ execvp()libc işlevi olabilir.

Diğer uygulamaların çoğu, bir komut çalıştırdıklarında bunlardan birini kullanır. Örneğin system("command line"), genellikle shkomut satırını (yolu derleme zamanında belirlenebilen ( Solaris'te /bin/shvs gibi /usr/xpg4/bin/sh)) ayrıştırmaya çalışacak olan libc işlevi aracılığıyla bir kabuk çağıracaklar veya $SHELLkendi başlarına depolanan kabukları çağıracaklar. vionun ile !komuta veya xterm -e 'command line've diğer birçok komutları ( su user -ckullanıcının giriş kabuğu yerine çağıracağı $SHELL).

Genel olarak, başlamamış, sessiz bir metin dosyası #bir shkomut dosyası olarak kabul edilir . Hangi sholsa değişecektir.

execlp()/ execvp(), execve()döndükten ENOEXECsonra genellikle shonu çağırır . shBirden fazla standarda uygun olabildikleri için birden fazla standarda sahip sistemler shiçin tipik olarak derleme zamanında belirlenecektir (uygulamanın farklı bir yola işaret eden farklı bir kod bloğunu kullanarak execvp()/ execlp()bağlayarak sh). Örneğin, Solaris'te bu /usr/xpg4/bin/sh(standart, POSIX sh) veya /bin/sh(Solaris 10 ve daha eski sürümlerde Bourne kabuğu (antika kabuk), Solaris 11'de ksh93) olacaktır.

Mermiler söz konusu olduğunda, çok fazla varyasyon var. bashAT & T ksh(sürece bir alt işleminde, Bourne Kabuk tipik olarak komut kendilerini yorumlayacaktır execkullanılmıştır), bir simüle sonra execve()tüm unexported değişkenler ayarlanmadan olduğu,,,, her yakın-on-exec fds kapalı tüm özel tuzakları çıkarıldı takma adlar, işlevler ... ( bashkomut dosyasını shmodda yorumlar). yash(kendini çalıştırır sholarak argv[0]öylesine de shbunu yorumlamak mod).

zsh, pdksh, ashMerkezli kabukları tipik olarak çağırır sh(derleme zamanında olan tespit yol).

İçin cshve tcsh(ve shbazı erken BSD türevi), dosyanın ilk karakteri ise #, o zaman kendileri yorumlamak, ve çalıştırır shaksi. Bu yorum olarak cshtanıdı #ama Bourne kabuğu değil, bir shebang öncesi zaman geri gider , bu yüzden #bir csh komut dosyası olduğunu bir ipucu oldu.

fish(en azından sürüm 2.4.0), execve()başarısız olursa bir hata döndürür (komut dosyası olarak ele almaya çalışmaz).

Bazı kabuklar ( bashAT&T veya AT&T gibi ksh) ilk önce sezgisel olarak dosyanın bir komut dosyası olup olmadığını belirlemeye çalışır. Yani, ilk birkaç baytta bir NUL karakteri varsa, bazı kabukların bir komut dosyasını çalıştırmayı reddedeceğini görebilirsiniz.

Ayrıca execve(), ENOEXEC ile başarısız olursa, ancak dosyanın bir shebang hattı varsa, bazı kabukların bu shebang hattının kendilerini yorumlamaya çalıştığını unutmayın.

Birkaç örnek:

  • Ne zaman $SHELLolduğunu /bin/bash, xterm -e 'myscript with args'olacak myscripttarafından yorumlanır bashiçinde shmod. İle birlikte xterm -e myscript with args, xtermkullanacak execvp()böylece script tarafından yorumlanacaktır sh.
  • su -c myscriptSolaris 10 üzerinde nerede rootbireyin giriş kabuğu /bin/shve /bin/shBourne kabuğu olacak olan myscriptBourne kabuk tarafından yorumlanır.
  • /usr/xpg4/bin/awk 'BEGIN{system("myscript")'Solaris 10 üzerinde yorumlayacaktır /usr/xpg4/bin/sh(aynı /usr/xpg4/bin/env myscript).
  • find . -prune -exec myscript {} \;Solaris 10'da (kullanma execvp()) POSIX ortamında bile (bir uyum hatası) /bin/shbile yorumlanacaktır /usr/xpg4/bin/find.
  • csh -c myscriptcshile başlarsa #, shaksi takdirde yorumlayacaktır .

Sonuç olarak, nasıl ve ne tarafından çağrılacağını bilmiyorsanız, bu komut dosyasını yorumlamak için hangi kabuğun kullanılacağından emin olamazsınız.

Her durumda, read -pbir bashemin komut tarafından yorumlanır emin olmak isteyeceksiniz yüzden, -sadece sözdizimi bash(ve bu yanıltıcı önlemek .shuzantısı). bashYürütülebilir dosyanın yolunu biliyor ve kullanıyorsunuz:

#! /path/to/bash -
read -p ...

Yoksa denemek ve bir güvenebilirsiniz $PATHait arama bashçalıştırılabilir (varsayarak bashkullanılarak yüklenir):

#! /usr/bin/env bash
read -p ...

( envneredeyse her yerde bulunur /usr/bin). Alternatif olarak, POSIX + Bourne uyumlu yapabilirsiniz, bu durumda kullanabilirsiniz /bin/sh. Tüm sistemlerde bir /bin/sh. Bunların çoğunda (çoğunlukla) POSIX uyumlu olacak, ancak şimdi ve sonra bir Bourne kabuğu bulabilirsiniz.

#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"

1

Herhangi bir #!( shebang adı verilen ) hattınız yoksa , sh kullanılır. Bunu kontrol etmek için aşağıdaki komut dosyasını çalıştırabilirsiniz.

ps -p $$
echo -n "The real shell is: "
realpath /proc/$$/exe

Bilgisayarımda

  PID TTY          TIME CMD
13718 pts/16   00:00:00 sh
The real program is: /usr/bin/bash

varsayılan kabuğum zsh olsa bile . Makinemde bash kullandığından , sh komutu bash tarafından uygulanır .


1
Bunu neden düşürdün? Lütfen açıklayın ya da işe yaramaz ...
rools

Nefret edenler (sessiz anonim inişler) nefret edecek. Cevabınızdan bir şey öğrendim, işte bir yukarı oy. :-)
Mac
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.