kabuk-betik başlıkları (#! / bin / sh vs #! / bin / csh)


92

Neden tüm komut dosyaları şu şekilde başlıyor?

#!/bin/sh

veya ile

#!/bin/csh

Bu gerekli mi? Bunun amacı nedir? Ve ikisi arasındaki fark nedir?


1
Bir csh betiği için #!/bin/csh -f; bu -f, kabuğa kullanıcının kaynağını oluşturmamasını söyler .loginve .cshrcbu da komut dosyasının daha hızlı çalışmasını sağlar ve kullanıcının kurulumuna olan bağımlılıkları önler. (Daha da iyisi, csh betikleri yazmayın.) -fSh veya bash betikleri için kullanmayın ; aynı anlama sahip değil.
Keith Thompson

Yanıtlar:


99

Bu şu şekilde bilinir Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! yorumlayıcı [isteğe bağlı-arg]

Bir shebang, yalnızca bir komut dosyasının yürütme iznine sahip olması durumunda geçerlidir (örneğin, chmod u + x script.sh).

Bir kabuk betiği çalıştırdığında, belirtilen yorumlayıcıyı kullanır.

Misal:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1

@Kolob Canyon gerekmez, ancak bazı editörlere sözdizimi vurgulama konusunda yardımcı olabilir (genellikle aynı şeyi başarmanın başka yolları olsa da): unix.stackexchange.com/a/88730/193985
Braham Snyder

42

#!Çizgi (özellikle, uygulanması çekirdek söyler execvebu program tercüme edilmiş bir dilde yazılmış olması sistem çağrısı); izleyen mutlak yol adı yorumlayıcıyı tanımlar. Makine koduna derlenen programlar, çoğu modern Unix'te 7f 45 4c 46( ^?ELF) onları bu şekilde tanımlayan farklı bir bayt dizisi ile başlar .

Sen mutlak bir yol koyabilirsiniz istediğiniz herhangi bir program sonrasında #!sürece bu program değil kendisi olduğu gibi, #!komut dosyası. Çekirdek, bir çağrıyı yeniden yazar.

./script arg1 arg2 arg3 ...

nerede ./script, ile başlar demek, #! /usr/bin/perlkomut satırı aslında olmuştu sanki

/usr/bin/perl ./script arg1 arg2 arg3

Ya da gördüğünüz #! /bin/shgibi yorumlanması amaçlanan bir senaryo yazmak için kullanabilirsiniz sh.

#!Eğer hat sadece işlenir doğrudan (komut dosyası çağırmak ./scriptkomut satırında); dosya da çalıştırılabilir olmalıdır ( chmod +x script). Bunu yaparsanız sh ./script, #!satır gerekli değildir (ve varsa yok sayılacaktır) ve dosyanın çalıştırılabilir olması gerekmez. Nokta özelliğinin onlar yazılır hangi dili bilmek zorunda kalmadan yorumlanır dil programlarına çağırmak doğrudan sizi sağlamaktır. (Do grep '^#!' /usr/bin/*- Sen pek çok stok programları bu özelliği kullanarak aslında olduklarını keşfedecek.)

İşte bu özelliği kullanmak için bazı kurallar:

  • #!İlk iki olmalıdır bayt dosyasında. Özellikle, dosya gerekir (örneğin UTF-8 çalışacaktır ancak UTF-16 will not) ASCII uyumlu kodlama olması ve olmamalıdır bir "bayt sırası işareti" ile başlar, ya da çekirdek a olarak tanımayacaktır #!senaryo.
  • Sonraki yol #!mutlak bir yol olmalıdır (ile başlar /). Boşluk, sekme veya yeni satır karakterleri içeremez.
  • İyi tarzıdır, fakat arasına bir boşluk koymak için gerekli #!ve /. Oraya birden fazla boşluk koymayın.
  • Kabuk değişkenlerini #!satıra koyamazsınız , genişletilmezler.
  • Mutlak yoldan sonra, ondan tek boşlukla ayrılmış bir komut satırı bağımsız değişkeni koyabilirsiniz . Mutlak yol gibi, bu bağımsız değişken de boşluk, sekme veya satırsonu karakterleri içeremez. Bazen bir şeylerin çalışması için bu gereklidir ( #! /usr/bin/awk -f), bazen sadece yararlıdır ( #! /usr/bin/perl -Tw). Ne yazık ki, mutlak yoldan sonra iki veya daha fazla argüman koyamazsınız .
  • Bazı insanlar #! /usr/bin/env interpreterbunun yerine kullanmanı söyleyecektir #! /absolute/path/to/interpreter. Bu neredeyse her zaman bir hatadır. Programınızın davranışını $PATH, komut dosyasını çalıştıran kullanıcının değişkenine bağlı kılar . Ve tüm sistemler envilk etapta sahip değildir .
  • İhtiyaç duyan setuidveya setgidayrıcalıklara sahip programlar kullanamaz #!; makine koduna derlenmeleri gerekir. (Ne olduğunu bilmiyorsanız setuidendişelenmeyin.)

İlgili csh, bu ilgilidir shkabaca Nutrimat olarak Gelişmiş Çay Yedek çaya yapar. Etkileşimli kullanıma göre shbir dizi avantajı vardır (ya da daha doğrusu; modern uygulamaları yakalamıştır) sh, ancak tcshkomut dosyası oluşturmak için onu (veya onun neslini ) kullanmak neredeyse her zaman bir hatadır . Genel olarak kabuk komut dosyası oluşturma konusunda yeniyseniz, bunu görmezden gelmenizi ve odaklanmanızı şiddetle tavsiye ederim sh. cshGiriş kabuğunuz olarak bir akraba kullanıyorsanız , bashveya seçeneğine geçin zsh, böylece etkileşimli komut dili öğrenmekte olduğunuz komut dosyası diliyle aynı olacaktır.


Linux'un son sürümleri, belirtilen yorumlayıcının bir betik olmasına izin veriyor. Şundan sonraki boşluğu çıkarmak yaygın bir uygulamadır #!; bunun iyi bir tarz olup olmadığı hakkında yorum yok. Bkz bu soruyu ve benim cevap artılarını ve eksilerini bir tartışma için #!/usr/bin/envhack.
Keith Thompson

@KeithThompson Ben izlenim altındayım Linux, yorumlayıcının bir betik olmasına izin veren tek yaygın Unix çeşididir, bu yüzden hala güvenilecek bir şey değil. Bunu yazdığımdan beri #!/usr/bin/envDoğru Şeyin olduğu bir durumla karşılaştım , ancak bana kalırsa bunun neredeyse her zaman kötü bir fikir olduğu.
zwol

4

Bu, komut dosyanızı yorumlamak / çalıştırmak için hangi kabuğu (komut yorumlayıcısı) kullandığınızı tanımlar. Her kabuk, kullanıcıyla etkileşim kurma ve komut dosyalarını (programları) çalıştırma biçiminde biraz farklıdır.

Unix komut istemine bir komut yazdığınızda, kabuk ile etkileşime girersiniz.

Örneğin, #!/bin/cshC kabuğunu, /bin/tcsht kabuğunu, /bin/bashbash kabuğunu vb. İfade eder.

Hangi etkileşimli kabuğu kullandığınızı anlayabilirsiniz.

 echo $SHELL

komut veya alternatif olarak

 env | grep -i shell

Komut kabuğunuzu komut ile değiştirebilirsiniz chsh.

Her birinin biraz farklı bir komut seti ve değişken atama yöntemi ve kendi programlama yapıları vardır. Örneğin, bash ile if-else ifadesi C-kabuğundakinden farklı görünüyor.

Bu sayfa , bash ve tcsh komutları / sözdizimi arasında "çeviri yaptığı" için ilgi çekici olabilir.

Yönergeyi kabuk betiğinde kullanmak, programları farklı bir kabuk kullanarak çalıştırmanıza izin verir. Örneğin, tcshkabuğu etkileşimli olarak kullanıyorum, ancak genellikle betik dosyasında / bin / bash kullanarak bash betikleri çalıştırıyorum.

Kenara:

Bu kavram diğer senaryolara da uzanıyor. Örneğin, Python'da program yapıyorsanız

 #!/usr/bin/python

Python programınızın en üstünde


Öyleyse gerekli mi? Gerçekte hangi kabuğu kullandığımı nasıl bilebilirim?
One Two Three

Yani birinin kendi makinesinde kullanması için komut dosyaları yazıyorsam ve hangi kabuğu kullandıklarını bilmiyorum. (Bu kişi maalesef bu konuda hiçbir fikre sahip değildir, bu yüzden yapabileceği tek şey hiçbir şeyi değiştirmeden senaryoyu çalıştırmaktır). Gibi bir şey yapabilir miyim #! $SHELL? Bu, Shebang'a doğru kabuğu koyar mı?
One Two Three

1
@OneTwoThree Çoğu sistemde standart kabuklar bulunur, eğer bir bash veya csh betiği yazarsanız sorun olmaz. Etkileşimli olarak hangi kabuğu kullandıkları önemli değil , bu örneğin !#/bin/bashdirektifin güzelliği . Sisteme, kabuk betiğinizi çalıştırmak için hangi kabuğun kullanılacağını söyler.
Levon

Değerinin $SHELLo anda hangi mermiyi çalıştırdığınızı size söylemesine gerek yoktur; normalde size varsayılan kabuğunuzu söyler . tcsh setleri $versionve $tcsh; bash setleri $BASH_VERSION. Tüm mermilerin benzer mekanizmaları olması gerekmez.
Keith Thompson

1
@OneTwoThree: #!Satır, komut dosyasını çalıştıran kişi tarafından kullanılan etkileşimli kabukla değil , komut dosyasının sözdizimiyle eşleşmelidir .
Keith Thompson
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.