#! / Bin / sh tercüman tarafından okunur mu?


66

İçinde bashveya sh, sanırım başlayan #bir yorum bir yorumdur .

Ama bashsenaryolarda biz yazıyoruz:

#!/bin/bash

Python betiklerinde de şunlar var:

#!/bin/python

Bu, #tek başına bir yorum #!olmadığı anlamına mı geliyor ?


1
Apparmor profillerine bakmaya başladığınızda göreceksiniz #include. Orada da, #bir yorum anlamına gelmez.

4
@ vasa1 Ancak, kabuk komut dosyalarının başlangıcındaki hashbang satırları hakkında genellikle takdir edilmeyen kilit nokta , yorum olmalarıdır .
Eliah Kagan

Yanıtlar:


100

#!Hat kullanıldığında önce komut dosyası çalıştırılır sonra ihmal, ne zaman komut dosyası çalışır.

Shebang çizgisi ile sıradan bir yorum arasındaki farkın ne olduğunu soruyorsun .

İle başlayan bir çizgi, ile başlayan #!herhangi bir diğer çizgi kadar bir yorumdur #. Bu, #!dosyanın ilk satırı veya başka bir yerde olması durumunda geçerlidir . #!/bin/sh bir etkisi var , ancak tercümanın kendisi tarafından okunmuyor .

#tüm programlama dillerinde bir yorum değildir, ancak bildiğiniz gibi, Bourne tarzı kabuklarda shve bash( ve çoğu Bourne tarzı olmayan kabuk gibi csh) bir yorumdur . Aynı zamanda Python'da bir yorum . Ve gerçekten hiçbir komut dosyası olmayan (gibi /etc/fstab) çeşitli yapılandırma dosyalarındaki bir yorumdur .

Bir kabuk betiğinin ile başladığını varsayalım #!/bin/sh. Bu bir yorumdur ve yorumlayıcı (kabuk) #karakterden sonra satırdaki her şeyi dikkate almaz .

Bir #!hattın amacı tercümana bilgi vermemektir. #!Çizginin amacı , işletim sistemine (veya tercümanı hangi işlem başlattıysa) tercüman olarak ne kullanılacağını söylemektir .

  • Eğer betiği çalıştırılabilir bir dosya olarak çağırırsanız, örneğin, çalıştırarak ./script.sh, sistem ilk satırına başlayıp başlamadığını #!, ardından sıfır veya daha fazla boşluk bırakıp ardından bir komutu takip edip etmediğini kontrol eder . Eğer öyleyse, bu komutu betiğin adı ile argüman olarak çalıştırır. Bu örnekte çalışır /bin/sh script.sh(veya teknik olarak /bin/sh ./script.sh).

  • Senaryoyu tercümanı açıkça çağırarak çağırırsanız, #!satıra asla danışılmaz. Yani, eğer kaçarsan sh script.sh, ilk çizginin etkisi olmaz. Eğer script2.shilk satır ise #!/usr/games/nibbles, çalışan sh script2.shbetiği açmaya çalışmayacaktır nibbles(ama ./script2.sholacaktır).

Her iki durumda da betiğin uzantısının ( .sh), birinin olması durumunda çalışma biçimini etkilemediğini fark edersiniz . Unix benzeri bir sistemde, bu normal olarak komut dosyasının nasıl çalıştığını etkilemez. Windows gibi bazı diğer sistemlerde, #!shebang satırı tamamen sistem tarafından yok sayılabilir ve uzantı, komut dosyalarını neyin çalıştığını belirleyebilir. (Bu, scriptlerinize uzantılar vermeniz gerektiği anlamına gelmez, ancak bunu yaparsanız doğru olmalarının sebeplerinden biridir.)

#!tam da bu amaca hizmet etmek için seçildi, çünkü # yorum yapmaya başladı. #!Hat sisteminin değil, tercüman için, ve yorumlayıcı tarafından göz ardı edilmelidir.

Bash Scriptleri için Shebang Line

Sen (aslında) sen senaryo #!/bin/shiçin kullandığını söylemiştin bash. Bunu sadece komut dosyası herhangi bir bashuzantıya shihtiyaç duymuyorsa yapmalısınız - komut dosyasını çalıştırabilmeniz gerekir. shher zaman bir sembolik bağlantı değildir bash. Çoğu zaman, üzerinde de dahil olmak üzere tüm uzaktan son Debian ve Ubuntu sistemleri , shsembolik köprü ise dash.

Python Scriptleri için Shebang Line

Ayrıca (sorunuzun ilk versiyonunda, düzenlemeden önce) Python komut dosyalarınızı başlattığınızı söylemiştiniz #!/bin/sh read by the interpretor. Kelimenin tam anlamıyla demek istiyorsan, kesinlikle bunu yapmayı bırakmalısın. Bu hello.pysatırla başlarsa , çalışan ./hello.pyçalıştırır:

/bin/sh read by the interpretor hello.py

/bin/shread( by the interpretor hello.pyargümanlarıyla birlikte) adlı bir komut dosyasını çalıştırmayı deneyecek read, (umarım) bulunmayacak ve Python komut dosyanız bir Python yorumlayıcısı tarafından asla görülmeyecektir.

Bu hatayı yapıyorsanız ancak tarif ettiğim bir sorunu yaşamıyorsanız, muhtemelen Python komut dizilerinizi tercümanı (örneğin python hello.py) açıkça belirterek ilk satırın yoksayılmasına neden olarak çağırıyorsunuz . Komut dosyalarınızı başkalarına dağıttığınız veya uzun bir süre sonra kullandığınız zaman, bunun çalışması için bunun gerekli olduğu açık olmayabilir. Onları şimdi düzeltmek en iyisidir. Ya da en azından ilk satırı tamamen kaldırın, böylece ./hata mesajı ile çalışamadıklarında mantıklı olurlar .

Python komut dosyaları için, Python yorumlayıcısının nerede olduğunu (veya olacağını) biliyorsanız, #!satırı aynı şekilde yazabilirsiniz :

#!/usr/bin/python

O bir Python 3 senaryo Ya da, sen belirtmelisiniz python3beri, pythonhemen hemen her zaman Python 2'dir :

#!/usr/bin/python3

Bununla birlikte, sorun /bin/shher zaman olması gerektiği ve işletim sistemi ile birlikte gelen /bin/bashsistemlerde neredeyse her zaman olduğu varsayılırken bash, Python çeşitli yerlerde var olabilir.

Bu nedenle, birçok Python programcısı bunun yerine bunu kullanır:

#!/usr/bin/env python

(Veya #!/usr/bin/env python3Python 3 için)

Bu, senaryoyu envdoğru yerde pythonolmak yerine "doğru yerde" olmaya dayandırır . Bu iyi bir şey çünkü:

  • envneredeyse her zaman içinde bulunur /usr/bin.
  • Çoğu sistemde, hangisini çalıştırmanız python gerektiğine bakılmaksızın, betiğinde ilk görünen PATH. Make run hello.pyile başlayan , (neredeyse) koşmaya eşdeğerdir .#!/usr/bin/env python./hello.py/usr/bin/env python hello.pypython hello.py

Kullanamamanın nedeni #!pythonşudur:

  • Belirtilen tercümanın mutlak bir yolla (yani ile başlayan /) verilmesini istiyorsunuz .
  • Çağıran işlem python mevcut dizinde yürütülür . Komut eğik çizgi içermediğinde yolu aramak belirli bir kabuk davranışıdır.

Bazen bir Python veya bir kabuk betiği olmayan başka bir komut dosyası, başka bir kodun #!/bin/sh ...bulunduğu yerden başlayarak bir shebang satırına sahip olacaktır .... Bu bazen doğrudur, çünkü Bourne uyumlu kabuğu ( sh) bir Python yorumlayıcısı çağırmak için argümanlarla çağırmanın bazı yolları vardır . (Argümanlardan biri muhtemelen içerecektir python.) Ancak, çoğu amaç için, #!/usr/bin/env pythondaha basit, daha zarif ve istediğiniz şekilde çalışması daha muhtemeldir.

Diğer Dillerde Shebang Çizgileri

Birçok programlama ve komut dosyası dili ve diğer bazı dosya formatları #yorum olarak kullanılır. Bunlardan herhangi biri için, dilde bir dosya, programı sonraki satırda belirterek argüman olarak alan bir program tarafından çalıştırılabilir #!.

Bazı programlama dillerinde #normal olarak bir yorum değildir, ancak özel bir durum olarak, ilk satır başlıyorsa yoksayılır #!. Bu, başka bir satırda bir yorum yapmamakla #!birlikte #, sözdiziminin kullanımını kolaylaştırır .

Shebang Scriptleri Olarak Çalışmayan Dosyalar için Satırlar

Daha az sezgisel olsa da, dosya formatı #!bir yürütülebilir satırın tam yolunu izleyen bir ilk satırı barındırabilen herhangi bir dosyada bir Shebang satırı olabilir. Bunu yaparsanız ve dosya çalıştırılabilir olarak işaretlenirse, bir program gibi çalıştırabilir ... bir belge gibi açılmasına neden olabilir.

Bazı uygulamalar bu davranışı bilerek kullanır. Örneğin, VMware'de .vmxdosyalar sanal makineleri tanımlar. Sanal bir makineyi bir komut dosyasıymış gibi çalıştırabilirsiniz "çünkü bu dosyalar çalıştırılabilir olarak işaretlenir ve bir VMware yardımcı programında açılmalarına neden olan bir shebang satırı vardır.

Shebang Satırları Komut Dosyaları Olarak Çalıştırılmıyor ancak Her Komut Dosyası Olarak Çalışıyor

rmdosyaları siler. Bir betik dili değil. Ancak, başlatılabilir #!/bin/rmve çalıştırılabilir olarak işaretlenmiş bir dosya çalıştırılabilir ve çalıştırdığınızda, dosyaya rmçağrılır ve silinir.

Bu genellikle "dosya kendini siler" olarak kavramsallaştırılır. Ancak dosya gerçekten hiç çalışmıyor. Bu daha yukarıda .vmxdosyalar için açıklanan duruma benzer .

Yine de, #!satır basit bir komutun çalıştırılmasını kolaylaştırdığından (komut satırı argümanları dahil), bu şekilde komut dosyası yazabilirsiniz. Şundan daha karmaşık bir "senaryo" örneği olarak #!/bin/rmdüşünün:

#!/usr/bin/env tee -a

Bu, kullanıcı girdisini etkileşimli olarak alır, kullanıcı satır satır tekrar eko yapar ve "script" dosyasının sonuna ekler.

İşe yarar? Çok değil. Kavramsal olarak ilginç? Kesinlikle! Evet. (Biraz.)

Kavramsal Olarak Benzer Programlama / Script Yazma Kavramları (sadece eğlence için)


@ Rinzwind Thx! (Bu cevap, merak ettiğiniz şey buysa başka bir yerden gelmez.)
Eliah Kagan

@Rinzwind Endişelenmeyin, 1 saat sonra 8 oy verme ile daha fazla yükseltme olasılığı var :-)
guntbert

1
Her zaman görmezden gelinirse, Pythons -xbayrağı ne yapar ?
gerrit

4
@gerrit İyi bir soru. Bilgisayar denetleyicisinin / derleyicinin satır numarasına sahip mesajları rapor ettiği herhangi bir dilde, yorumların içeriği dikkate alınmaz, ancak yorum satırları hala sayılır . Bir kod satırından önce bir yorum veya boş bir satır eklemek, kod satırının artmasına neden olan bir kod satırına neden olur. -x"ilk satırı atla ...", 2. satır 1yerine 2. satır 2, 3. satır 2yerine 3vb. bu bayrağı kullanmamalısınız. ;) -xbaşlamadan başlayarak shebang benzeri bir sözdizimine sahip Unix benzeri olmayan işletim sistemlerinde komut dosyası yazmak içindir #(dolayısıyla bir Python yorumu değil).
Eliah Kagan,

4
Tercüman (doğrudan başlatılıp başlatılmadığını Perl olarak, perl script.plvs ./script.pl) daha sonra tercüman olacak gibi bayraklarını ayrıştırmak için shebang satır okuyun -w. Yine de bu özelliğe güvenmeniz önerilmez.
OrangeDog

7

Bir shebang, bir betiğin ilk satırında ilk iki karakter olarak gerçekleştiğinde karakter sayı işaretinden ve ünlem işaretinden (örneğin, "#!") Oluşan karakter dizisidir.

* Nix işletim sistemlerinde, bir shebang ile başlayan bir komut dosyası çalıştırıldığında, program yükleyici, komut dosyasının ilk satırının bir tercüman yönergesi olarak ayrıştırılmasını sağlar; Bunun yerine, belirtilen tercüman programı, betiği çalıştırmaya çalışırken başlangıçta kullanılan yolu argüman olarak ileterek çalıştırılır. Örneğin, bir komut dosyası "path / to / your-script" yoluyla adlandırılmışsa ve aşağıdaki satırla başlarsa:

#!/bin/sh

daha sonra program yükleyiciye, "Bour / Shell" yerine "/ bin / sh" programını çalıştırması istenir, örneğin "path / to / your-script" 'in ilk argümanı olarak geçirilir.

Buna göre, bir komut dosyası "path / to / python-script" yoluyla adlandırılır ve aşağıdaki satırla başlar:

#!/bin/python

daha sonra yüklenen programın yerine "/ bin / python" programını çalıştırması istenir, örneğin Python yorumlayıcısı, "path / to / python-script" i ilk argüman olarak geçerek.

Kısacası "#" karakter sırasını "#!" Bir betiğin ilk satırında ilk iki karakter olarak gerçekleşen, yukarıda belirtildiği gibi anlamına gelir.

Ayrıntılar için, bkz. Neden bazı komut dosyaları #! ...?

Kaynak: Bu cevabın bazı bölümleri dan (ufak bir değişiklikle) türetilmiştir shebang (Unix) üzerine İngilizce Vikipedi (tarafından Vikipedi katkıda ). Bu makale, CC-BY-SA 3.0 kapsamında , burada AU'daki kullanıcı içeriğiyle aynı şekilde lisanslanmıştır , bu nedenle bu türetmeye atıfta bulunulmasına izin verilir.


4

#!shebangBir betiğin ilk satırında ilk iki karakter olarak gerçekleştiğinde denir . Kodlarda, yürütme için bir tercüman belirtmek amacıyla kullanılır. shebangKabuksuz için işletim sistemi (çekirdek), içindir; bu yüzden yorum olarak yorumlanmayacak.

Nezaket: http://en.wikipedia.org/wiki/Shebang_%28Unix%29

Genel olarak, eğer bir dosya çalıştırılabilir, ancak aslında çalıştırılabilir (ikili) bir program ve böyle bir satır mevcut değilse, #! scriptname ve tüm argümanları ile başlar. Bu iki karakter # ve! dosyadaki ilk iki bayt olmalı!

Ayrıntılı Bilgi: http://wiki.bash-hackers.org/scripting/basics#the_shebang


0

Hayır, sadece execLinux çekirdeğinin sistem çağrısı tarafından kullanılır ve yorumlayıcı tarafından yorum olarak kabul edilir.

Bash yaparken:

./something

Linux'ta, bu execsistem çağrısı yolu ile çağırır ./something.

Çekirdeğin bu satırı iletilen dosyaya çağrılır exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

Dosyanın ilk baytlarını okur ve karşılaştırır #!.

Karşılaştırma doğruysa, satırın geri kalanı Linux çekirdeği tarafından ayrıştırılır; bu , ilk bağımsız değişken olarak execpath /usr/bin/env pythonve current dosyasıyla başka bir çağrı yapar :

/usr/bin/env python /path/to/script.py

ve bu #, yorum karakteri olarak kullanılan herhangi bir komut dosyası dili için işe yarar .

Ve evet, ile sonsuz bir döngü yapabilirsiniz:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash hatayı tanır:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! sadece insan tarafından okunabilir olur, ancak bu gerekli değildir.

Dosya farklı baytlarla execbaşlarsa , sistem çağrısı farklı bir işleyici kullanır. Diğer en önemli dahili işleyici ELF çalıştırılabilir dosyalar için geçerli: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 bayt kontrolü yaptığı 7f 45 4c 46aynı zamanda insan olur ki ( için okunabilir .ELF). /bin/lsELF çalıştırılabilir olan ilk 4 baytı okuyarak onaylayalım :

head -c 4 "$(which ls)" | hd 

çıktı:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

Böylece, çekirdek bu baytları gördüğünde, ELF dosyasını alır, doğru şekilde belleğe koyar ve onunla yeni bir işlem başlatır. Ayrıca bakınız: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

Sonunda, kendi Shebang işleyicilerini binfmt_miscmekanizma ile ekleyebilirsin . Örneğin, dosyalar için özel bir işleyici.jar ekleyebilirsiniz . Bu mekanizma, dosya uzantısına göre işleyicileri bile destekler. Başka bir uygulama, farklı bir mimarinin yürütülebilirlerini şeffaf bir şekilde QEMU ile çalıştırmaktır .

POSIX'in shebang'ları belirttiğini sanmıyorum: rasyonel bölümlerde ve çalıştırılabilir komut dosyaları sistem tarafından destekleniyorsa rasyonel bölümlerde ve formda belirtilmiş olmasına rağmen, https://unix.stackexchange.com/a/346214/32558. olmak".

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.