Çok fazla shebang (script beyanı) satırı - miktarlarını azaltmanın herhangi bir yolu var mı?


12

Yaklaşık 20 küçük .shdosyadan oluşan bir projem var . Bu "küçük" olarak adlandırıyorum çünkü genellikle hiçbir dosya 20'den fazla kod satırına sahip değil Modüler bir yaklaşım izledim çünkü Unix felsefesine sadık kaldım ve projeyi sürdürmem daha kolay.

Her .shdosyanın başlangıcına koydum #!/bin/bash.

Basitçe söylemek gerekirse, senaryo bildirimlerinin iki amacı olduğunu anlıyorum:

  1. Kullanıcının dosyayı yürütmek için hangi kabuğa ihtiyaç duyduğunu hatırlamasına yardımcı olur (örneğin, dosyayı kullanmadan birkaç yıl sonra).
  2. Başka bir kabuk kullanılması durumunda beklenmedik davranışı önlemek için komut dosyasının yalnızca belirli bir kabukla (bu durumda Bash) çalışmasını sağlarlar.

Bir proje 5 dosyadan 20 dosyaya veya 20 dosyadan 50 dosyaya büyümeye başladığında (bu durumda değil, sadece göstermek için) 20 satır veya 50 satır komut dosyası bildirimimiz var. Kabul ediyorum, bazıları için komik olsa da, 20 veya 50 kullanmak benim için biraz gereksiz geliyor, bunun yerine proje başına sadece 1 demek (belki de projenin ana dosyasında ).

Bazı ana dosyalarda "global" komut dosyası bildirimi kullanarak bu 20 veya 50 fazlalık olduğu iddia edilen fazlalık veya çok daha fazla sayıda komut dosyası bildirimi satırından kaçınmanın bir yolu var mı?


2
Yapmamalı ama yapmalısın; kaldırın ve tüm komut dosyalarınızı yürütün/bin/bash -x "$script"
jesse_b


... Genellikle bir şey bu noktaya geldiğinde, kabuk komut dosyalarını kullanmayı bırakmanın ve işi yapmak için gerçek bir komut dosyası dilini alma zamanının geldiğine karar verdim.
Shadur

Yanıtlar:


19

Projeniz artık yalnızca 50 Bash betiğinden oluşabilse de, er ya da geç Perl veya Python gibi diğer dillerde yazılmış komut dosyalarını biriktirmeye başlayacaktır (bu komut dillerinin Bash'in sahip olmadığı faydalar için).

#!Her komut dosyasında uygun bir satır olmadan , hangi komut dosyasının kullanılacağını bilmeden çeşitli komut dosyalarını kullanmak son derece zor olacaktır . Her komut dosyasının diğer komut dosyalarından yürütülmesi önemli değildir , bu sadece zorluğu son kullanıcılardan geliştiricilere taşır. Bu iki gruptan hiçbirinin bir betiğin kullanabilmesi için hangi dilde yazılmış olduğunu bilmeleri gerekmez.

#!-Line ve açık bir yorumlayıcı olmadan yürütülen kabuk komut dosyaları , hangi kabuğun onları çağırdığına bağlı olarak farklı şekillerde yürütülür (örneğin, hangi kabuk yorumlayıcısının hiç kodsuz bir komut dosyası çalıştırdığı sorusuna ve özellikle Stéphane'nin cevabı ), ki bu sizin istediğiniz şey değildir bir üretim ortamında (tutarlı bir davranış ve hatta taşınabilirlik istersiniz).

Açık bir tercümanla yürütülen komut dosyaları, #!-line'ın söylediklerinden bağımsız olarak söz konusu tercüman tarafından çalıştırılır . Python veya başka bir dilde bir Bash betiği yeniden uygulamaya karar verirseniz, bu durum sorunlara neden olur.

Bu ekstra tuş vuruşlarını harcamalı #!ve her komut dosyasına her zaman bir- satır eklemelisiniz .


Bazı ortamlarda, her projedeki her komut dosyasında çok paragraflı ortak metin yasal metinler bulunur. Sadece #!projenizde "gereksiz" hissettiren bir -line olduğundan çok mutlu olun .


Yanıt şu şekilde genişletilmelidir: Kabuk #!, dosyanın izin verilen izni olduğunda ve bir yorumlayıcı tarafından değil, kabuk tarafından yüklendiğinde yorumlayıcıyı satır tarafından belirler . Yani, çizgi /path/to/myprog.plvarsa #!(perl yorumlayıcısına işaret eder) ve dosya yürütme iznine sahipse perl programını çalıştırır .
rexkogitans

11

Amacını yanlış anlıyorsun #!. Bu programı tanımlı tercüman altında çalıştırmak aslında işletim sistemine bir direktiftir .

Böylece bir komut dosyası olabilir #!/usr/bin/perlve ortaya çıkan program olarak çalıştırılabilir ./myprogramve perl yorumlayıcısı kullanılabilir. Benzer #!/usr/bin/pythonbir program python altında çalışmasına neden olur.

Böylece hat #!/bin/bash, işletim sistemine bu programı bash altında çalıştırmasını söyler.

İşte bir örnek:

$ echo $0
/bin/ksh

$ cat x
#!/bin/bash

ps -aux | grep $$

$ ./x
sweh      2148  0.0  0.0   9516  1112 pts/5    S+   07:58   0:00 /bin/bash ./x
sweh      2150  0.0  0.0   9048   668 pts/5    S+   07:58   0:00 grep 2148

Kabuğum ksh olmasına rağmen, "x" programı #!satır yüzünden bash altında çalışıyor ve bunu açıkça işlem listesinde görebiliyoruz.


ps -auxuyarı verebilir,
Weijun Zhou

@WeijunZhou Say more more
Kusalananda

Bazı sürümleri psuyarı verir Warning: bad syntax, perhaps a bogus '-'?.
Weijun Zhou

2
pshem suooprts BSD ve UXIX argüman sözdizimi. -auxyanlış UNIX Stephen muhtemelen auxdoğru olan BSD anlamına gelir
Jasen

1
İnsanlar, 2 şey; (1) açık sözdizimine değil, örnek kavramına ( psçağrıldığını gösterir ) odaklanın bash; (2) ps -auxuyarı yapmadan CentOS 7 ve Debian 9 üzerinde mükemmel çalışır; o cut'n'paste tam olarak makinemden çıktıydı; -gerekli olup olmadığının tüm tartışması, mevcut sürümler için değil, linux procps'in eski sürümleri için geçerliyse.
Stephen Harris

9

üzerinde .sh

Kötü .sholan, dosya adının sonundaki.

Python'daki komut dosyalarından birini yeniden yazdığınızı düşünün.

Şimdi, ilk satırı değiştirmek zorundasınız #!/usr/bin/python3ki dosyadaki diğer tüm kod satırlarını da değiştirmek zorunda kaldınız. Ancak aynı zamanda dosya adını değiştirmek zorunda prog.shiçin prog.py. Ve sonra diğer komut dosyalarının her yerinde ve tüm kullanıcı komut dosyalarınızda (var olduğunu bile bilmediğiniz kodlar) bulmanız ve bunları yeni komut dosyasını kullanacak şekilde değiştirmeniz gerekir. sed -e 's/.sh/.py/g'bildiklerinize yardımcı olabilir. Ama şimdi revizyon kontrol aracınız ilgisiz birçok dosyada bir değişiklik gösteriyor.

Alternatif bunu Unix yol yapmak ve programı isim progdeğil prog.sh.

üzerinde #!

Doğru varsa #!ve yürütme dahil izin / mod ayarlayın. O zaman tercümanı bilmenize gerek yoktur. Bilgisayar bunu sizin için yapacak.

chmod +x prog #on gnu adds execute permission to prog.
./prog #runs the program.

Gnu olmayan sistemler için chmod, belki de yine de okuyun.


1
Hmmm, uzantılar mutlaka kötü değil, en azından dosya türü nedir diğer kullanıcılarla iletişim kurmaya yardımcı oluyorlar.
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy Ama dili bilmenize gerek yok, sadece çalıştırmanız gerekiyor. Microsoft bile uzantılardan uzaklaşmaya çalışıyor (maalesef bunu onları saklıyorum). Ancak iyi bir fikir olabileceğini kabul ediyorum: .imageresimler için. .audioBöylece uygulama / kodlama ile ilgili değil, ne olduğunu anlatmak.
ctrl-alt-delor

1
@ ctrl-alt-delor Dosya çağrılırsa launch-missilesveya delete-project-and-make-manager-pissedyalnızca dil hakkında merak ettiğimde "sadece çalıştırmak" istemezseniz
Sergiy Kolodyazhnyy

2
Eğer dili merak ediyorsanız filekomutu kullanın. çoğu dosya türünü tanır.
Jasen

2
Tam olarak verilen nedenlerden dolayı uzantıların yürütülebilir komut dosyaları için kötü olduğunu kabul ediyorum. Başka bir kabuk komut dosyası (yani yürütülebilir olmayan bir komut dosyası) tarafından kaynaklanması gereken bir komut dosyası için .sh uzantısı kullanıyorum - bu senaryoda, sonek önemli / geçerli çünkü dosyayı nasıl kullanabileceğimizi anlatıyor.
Laurence Renshaw

8

[Hashbang satırları] , başka bir kabuk kullanılması durumunda beklenmedik davranışı önlemek için komut dosyasının yalnızca belirli bir kabukla (bu durumda Bash) çalışmasını sağlar.

Muhtemelen bunun oldukça yanlış olduğunu belirtmeye değer. Hashbang satırı hiçbir şekilde dosyayı yanlış bir kabuk / yorumlayıcıya beslemeye çalışmanızı engellemez:

$ cat array.sh
#!/bin/bash
a=(a b c)
echo ${a[1]} $BASH_VERSION
$ dash array.sh
array.sh: 2: array.sh: Syntax error: "(" unexpected

(veya benzer şekilde awk -f array.shvb.)


Ancak her durumda, modülerliğe başka bir yaklaşım, dosyalarda kabuk işlevlerini, isterseniz dosya başına bir işlevi ve daha sonra sourceana programdaki dosyaları tanımlamak olacaktır . Bu şekilde, hashbang'lara ihtiyacınız olmaz: diğer yorumlar olarak ele alınır ve her şey aynı kabuğu kullanarak çalışır. Dezavantajı source, işlevlere (örneğin for x in functions/*.src ; do source "$x" ; done) sahip dosyalara ihtiyacınız olacaktır ve hepsi aynı kabuğu kullanarak çalışacaktı, bu yüzden bunlardan birini doğrudan Perl uygulamasıyla değiştiremediniz.


+1, örneğin bash dizileriyle. Çoklu mermilere veya POSIX'in tanımladığı şeylere aşina olmayan kullanıcılar, bir merminin bazı özelliklerinin başka bir kabukta var olduğunu varsayabilir . Ayrıca işlevler için bu ilgili olabilir: unix.stackexchange.com/q/313256/85039
Sergiy Kolodyazhnyy

4

Bazı ana dosyalarda "global" komut dosyası bildirimi kullanarak bu 20 veya 50 fazlalık olduğu iddia edilen fazlalık veya çok daha fazla sayıda komut dosyası bildirimi satırından kaçınmanın bir yolu var mı?

Var - buna taşınabilirlik veya POSIX uyumluluğu denir. Komut dosyalarını her zaman taşınabilir, kabuktan bağımsız bir şekilde yazmaya çalışın, bunları yalnızca kullanan bir komut dosyasından #!/bin/shveya /bin/shetkileşimli olarak kullandığınızda (veya en azından POSIX uyumlu bir kabuk gibi ksh) kaynaklayın.

Ancak, taşınabilir komut dosyaları sizi şunlardan kurtarmaz:

  • mermilerden birinin özelliklerini kullanma ihtiyacı ( ilkkachu'nun cevabı bir örnektir)
  • komut dosyası dillerini kabuklardan daha gelişmiş (Python ve Perl) kullanma ihtiyacı
  • PEBKAC hatası: komut dosyanız, komut dosyanızı istediğiniz gibi çalıştıran J.Doe kullanıcısının ellerine düşer , örneğin /bin/shkomut dosyasını çalıştırırlar csh.

Eğer fikrimi ifade edebilirsem, “fazlalıktan kaçınarak” ortadan kaldırarak #!yanlış hedeftir. Amaç tutarlı bir performans olmalı ve aslında çalışan ve köşe vakalarını dikkate alan çalışan bir komut dosyası , ayrıştırma-ls veya her zaman-tırnak-değişkenler-gerek duymadıkça kelime-bölme gibi bazı genel kuralları izlemelidir .

Kullanıcının dosyayı yürütmek için hangi kabuğa ihtiyaç duyduğunu hatırlamasına yardımcı olur (örneğin, dosyayı kullanmadan birkaç yıl sonra).

Gerçekten kullanıcı için değiller - işletim sisteminin doğru yorumlayıcıyı çalıştırması için. Bu durumda "Uygun", OS'nin şeyhte ne bulduğunu gösterir; altında kod yanlış kabuk için ise - bu yazarın hatası. Kullanıcı belleğine gelince, Microsoft Word veya Google Chrome gibi programların "kullanıcısının" hangi dil programlarının yazıldığını bilmesi gerektiğini düşünmüyorum; yazarlar gerekebilir.

Daha sonra, portatif olarak yazılan komut dosyaları, orijinal olarak hangi kabuğu kullandığınızı hatırlama ihtiyacınızı bile ortadan kaldırabilir, çünkü taşınabilir komut dosyaları herhangi bir POSIX uyumlu kabukta çalışmalıdır.

Başka bir kabuk kullanılması durumunda beklenmedik davranışı önlemek için komut dosyasının yalnızca belirli bir kabukla (bu durumda Bash) çalışmasını sağlarlar.

Yapmazlar. Aslında beklenmedik davranışları engelleyen şey taşınabilir komut dosyaları yazmaktır.


1

#!/bin/bashHer komut dosyasının en üstüne koymanızın nedeni , onu ayrı bir işlem olarak çalıştırmanızdır.

Bir komut dosyasını yeni bir işlem olarak çalıştırdığınızda, işletim sistemi bunun bir metin dosyası (ikili yürütülebilir dosyanın aksine) olduğunu görür ve hangi yorumlayıcıyı yürüteceğini bilmelidir. Bunu söylemezseniz, işletim sistemi yalnızca varsayılan ayarını (bir yöneticinin değiştirebileceği) kullanarak tahmin edebilir. Bu nedenle #!satır (artı yürütülebilir izinler eklenmesi elbette) basit bir metin dosyasını doğrudan çalıştırılabilen bir yürütülebilir dosyaya dönüştürür.

#!Çizgiyi kaldırmak istiyorsanız , seçenekleriniz şunlardır:

  1. Komut dosyasını doğrudan yürütün (şu anda yaptığınız gibi) ve varsayılan yorumlayıcının komut dosyasıyla eşleştiğini umarsınız - muhtemelen çoğu Linux sisteminde güvende olursunuz, ancak diğer sistemlere (örneğin Solaris) taşınabilir değildir ve şu şekilde değiştirilebilir: herhangi bir şey (ben bile vimdosyayı çalıştırmak için ayarlayabilirsiniz !).

  2. Komut dosyasını kullanarak çalıştırın bash myscript.sh. Bu iyi çalışıyor, ancak komut dosyasının yolunu belirtmeniz gerekiyor ve dağınık.

  3. Kaynak komut dosyası kullanarak . myscript.sh(bir alt süreç olarak yani değil) geçerli tercüman süreci içinde komut dosyasını çalıştırır. Ancak bu neredeyse komut dosyalarınızda değişiklik yapılmasını gerektirecek ve onları daha az modüler / yeniden kullanılabilir hale getirecektir.

Durum 2 ve 3'te, dosyanın yürütme izinlerine ihtiyacı yoktur (ve olmamalıdır) ve dosyaya .sh(veya .bash) sonek vermek iyi bir fikirdir.

Ancak, komut dosyalarınızı modüler (=> bağımsız ve bağımsız) tutmak istediğinizi söylediğiniz gibi, bu seçeneklerin hiçbiri projeniz için iyi görünmüyor, bu nedenle #!/bin/bashsatırınızı komut dosyalarının üstünde tutmalısınız .

Sorunuzda, Unix felsefesini takip ettiğinizi de söylediniz. Bu doğruysa, #!satırın gerçekten ne için olduğunu öğrenmeli ve her yürütülebilir komut dosyasında kullanmaya devam etmelisiniz !


Güzel cevap için teşekkürler. Ben cevap her şeyi sevdi ve bu kadar upvoting düşündüm: then you should learn what the #! line is really for, and keep using it in every executable script!. İnsan felsefesini belirli bir bilgi noktasına kadar takip edebilir. Tüm bu cevaplardan sonra neden bu terime dahil edilebileceğini anladım. Cevabı değiştirmenizi ve "Saygıyı, saygı duyduğunuz ve benimsediğiniz Unix Felsefesinin bir parçası olarak görün" ile değiştirmenizi öneririm.
user9303970

1
Doğrudan olsaydım ya da bu yorum kaba görünüyorsa özür dilerim. Yorumlarınız, bir IDE'de çalışmayı tercih etti - bu proje içindeki komut dosyaları için genel kuralları tanımlamanızı sağlayan bir 'proje' ile. Bu gelişmenin geçerli bir yoludur, ancak her betiğe bağımsız, bağımsız bir program (bahsettiğiniz Unix felsefesi) olarak davranılması uygun değildir.
Laurence Renshaw
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.