Yanıtlar:
Bu, neden yazmanız gerektiğine benzer bir nedenden dolayı:
rm -- *.txt
Ve yok
rm *.txt
.txtGeçerli dizindeki dosyaların hiçbirinin ile başlayan bir adı olmadığını garanti edemezseniz -.
İçinde:
rm <arg>
<arg>Başladığında bir seçenek olarak kabul edilir, -aksi takdirde kaldırmak için bir dosya. İçinde
rm - <arg>
argher zaman başlayıp başlamamasına bakmaksızın kaldırılacak bir dosya olarak kabul edilir -.
Bunun için aynı sh.
Biri ile başlayan bir komut dosyasını çalıştırdığında
#! /bin/sh
Tipik olarak:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Sistem onu dönüştürür:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
Bu path/to/the-scriptgenellikle senaryo yazarının kontrolü altında olan bir şey değildir. Yazar, senaryonun kopyalarının nerede saklanacağını veya hangi isim altında olacağını tahmin edemez. Özellikle, path/to/the-scriptçağrıldığı şeyin başlayamayacağını -(veya bununla +ilgili bir sorun olmadığını) garanti edemezler sh. Biz bu yüzden gerek- seçeneklerin sonunu işaretlemek için buraya.
Örneğin, sistemimde zcat(aslında diğer çoğu komut dosyası gibi) bu tavsiyeye uymayan bir komut dosyası örneğidir:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Şimdi neden isteyebilir #! /bin/sh -değil #! /bin/sh --?
İken #! /bin/sh --POSIX kabukları ile çalışacak, #! /bin/sh -daha taşınabilir olduğu; özellikle eski versiyonlara sh. seçeneklerin ön-öncesi ve sonları gibi shdavranmak -ve seçeneklerin sonunu uzun süre işaretlemek için getopt()genel kullanımı --. Bourne kabuğunun (70'li yılların sonlarından itibaren) argümanlarını ayrıştırma şekli, ilk başladığında seçenekler için sadece ilk argüman dikkate alındı -. Ardından gelen tüm karakterler -seçenek adları olarak kabul edilir; Bundan sonra karakter -olmazsa, seçenek yoktu. Sıkışmış ve daha sonra Bourne benzeri mermiler -, seçeneklerin sonunu işaretlemenin bir yolu olarak görüyor.
Bourne kabuğunda (ancak modern Bourne benzeri mermilerde değil), #! /bin/sh -eufsadece ilk argüman seçenekler için düşünüldüğü için problemi çözer.
Şimdi, kişi burada bilgiçlik ettiğimizi söyleyebilir ve bu yüzden yukarıdaki italik ihtiyacını yazdım :
-veya +veya Adını başlar bir dizine koyun -veya +.execvp()/ execlp()-type işlevlerinden kaynaklanmayacağını iddia ederdi . Ve bu durumda, genellikle onları the-scriptaranacak şekilde çağırırsınız $PATH; bu durumda execve()sistem çağrısına giden yol argümanı tipik olarak /( -ne de değil +) ile başlayacaktır veya geçerli dizinde çalıştırılmasını ./the-scriptistiyorsanız the-script(ve sonra yol ya da ./hiçbiri ile başlar .-+Şimdi teorik doğruluk konusunun yanında, iyi uygulama#! /bin/sh - olarak önerilmesinin bir başka nedeni daha var . Ve bu, birkaç sistemin hala setuid betiklerini desteklediği bir zamana kadar uzanıyor.
Aşağıdakileri içeren bir komut dosyanız varsa:
#! /bin/sh
/bin/echo "I'm running as root"
Ve bu betik, -r-sr-xr-x root binsıradan bir kullanıcı tarafından yürütüldüğünde, bu sistemlerde ( izinlerde olduğu gibi ) setuid root
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
olarak yapılacaktı root!
Kullanıcı bir sembolik bağlantı oluşturup /tmp/-i -> path/to/the-scriptbunu uyguladıysa -i, interaktif bir kabuk ( /bin/sh -i) olarak başlayacaktır root.
-(Bu geçici bir çözüm olmaz geçici olacağını yarış koşulu sorununu veya bazı gerçeğini shbazıları gibi uygulamalar ksh88tabanlı olanlar komut dosyası değişkenlerini arama ediyorum /içinde $PATHolsa da).
Günümüzde neredeyse hiç sistem desteği setuid komut artık ve (varsayılan olarak genellikle) hala sitelerde ise bazı yapıyor sonunda bir execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])(burada <n>etrafında bu sorunu hem çalışır senaryo üzerinde okumak için açık bir dosya belirleyicisidir) yarış kondisyonu.
Sadece Bourne benzeri mermilerle değil, çoğu tercümanla da benzer sorunlar yaşadığınızı unutmayın. Bourne benzeri olmayan kabuklar genellikle -seçenek sonu işaretçisi olarak desteklemez, ancak --bunun yerine genellikle desteklenir (en azından modern sürümler için).
Ayrıca
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Bir sonraki argüman için bir argüman olarak kabul edilir olarak sorunu yok mu -fher durumda seçeneği, ama eğer hala çalışmıyor path/to/scriptise -(bu durumda, çoğu sed/ awkuygulamaları, sed/ awkkod okumaz -dosya, ancak bunun yerine stdin).
Ayrıca çoğu sistemde birinin kullanamayacağına dikkat edin:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Çoğu sistemde olduğu gibi, shebang mekanizması yorumlayıcı yolundan sonra yalnızca bir argümana izin verir .
#! /bin/sh -Vs kullanılıp kullanılmayacağına gelince #!/bin/sh -, bu sadece bir zevk meselesi. Tercüman yolunu daha görünür ve fare seçimini kolaylaştıracağı için eskisini tercih ederim. Boşluğa bazı eski Unix versiyonlarında ihtiyaç duyulduğunu söyleyen bir efsane var ama AFAIK, hiç doğrulanmadı.
Unix shebang hakkında çok iyi bir referans https://www.in-ulm.de/~mascheck/various/shebang adresinde bulunabilir.
bashher diğer kabuk gibi seçenekleri kabul eder. Bourne benzeri ve POSIX kabuğu olan, bashhem de kabul eder #! /bin/bash -ve #! /bin/bash --.