Bourne kabuğu bir dağıtımda yoksa hashbang / bin / sh komutunu kullanmak doğru mudur?


15

Genellikle, kabuk komut komut dosyasının ilk satırında aşağıdaki yorumu içerir: #!/bin/sh. Yaptığım araştırmalara göre, buna "karma patlama" deniyor ve geleneksel yorum. Bu yorum Unix'e bu dosyanın Bourne Shell tarafından dizinin altında yürütüldüğünü bildirir /bin.

Sorum o noktada başlıyor. Şimdiye kadar bu yorumu beğenmedim #!/bin/bash. Her zaman öyledir #!/bin/sh. Ancak, Ubuntu dağıtımlarında Bourne Shell programı yoktur. Bourne Again Shell'e (bash) sahipler.

Bu noktada, yorumu #!/bin/shUbuntu dağıtımlarında yazılan kabuk komut dosyalarına yerleştirmek doğru mudur?


4
AKA
shebang

1
Bu sunucuya verilen soruya cevabımı görün: Maksimum taşınabilirlik için #! / Bin / sh vs #! / Bin / bash .
Gordon Davisson

Daha yaygın olarak adlandırılanshebang
fpmurphy

Yanıtlar:


16

#!/bin/shtüm Unix ve Unix benzeri dağıtımlarda çalışmalıdır. Komut dosyanız POSIX uyumlu olduğu sürece genellikle en taşınabilir hashbang olarak düşünülür. /bin/shKabuk bakılmaksızın gerçek kabuk olarak bu maskeli ne olduğu, uygular POSIX standart kabuk bir kabuk olması gerekiyordu /bin/shkabuk.


#!/bin/shBourne kabuğu artık korunmadığından normalde artık sadece bir bağlantıdır. Birçok Unix sisteminde /bin/shbir bağlantı olacak /bin/kshveya /bin/ashbirçok RHEL tabanlı Linux sisteminde bir bağlantı olacak /bin/bash, ancak Ubuntu ve birçok Debian tabanlı sistemde bir bağlantı olacak /bin/dash. Tüm kabuklar, çağrıldığında shPOSIX uyumluluk moduna girer.

Hashbang önemli bir yer tutucudur, çünkü komut dosyanız kesinlikle POSIX uyumlu (stres önemine tekrarlanan) olduğu sürece diğer yöntemlerden çok daha fazla taşınabilirliğe izin verir.

Not: bashPOSIX modunda çağrıldığında [[, diziler, vb. Gibi POSIX olmayan bazı şeylere izin verilir . Bu şeyler bir bashsistem dışı sistemde başarısız olabilir .


3
"Ubuntu'da / bin / dash bağlantısı ve genel olarak diğer Debian tabanlı sistemler. FreeBSD / GhostBSD üzerinde IIRC de bir symlink /bin/ash.
Sergiy Kolodyazhnyy

Tamamen portatif olabilmek için, mesele ile (mutlak) tercüman yolu arasına bir boşluk bırakın. Bazı sistemler #! /sadece yerine bakar #!.
Simon Richter

5
@SimonRichter Bunun için bir referans görmek güzel olurdu.
Kusalananda

@SergiyKolodyazhnyy FreeBSD'de sh'in kurulu sürümü bir symlink değil kültir.
Rob

2
@Kusalananda, hmm, bu sayfa bunun bir efsane olduğunu söylüyor, bu yüzden muhtemelen göz ardı edilebilir.
Simon Richter

12

Geri aldın. /bin/shbu günlerde neredeyse hiç Bourne kabuğu değildir ve o zaman, bir dişi #! /bin/shpatlama kullandığınızda bir probleminiz vardır .

Bourne kabuğu, 70'lerin sonlarında yazılmış ve önceki Thompson kabuğunun (aynı zamanda da denir sh) yerini alan bir kabuktu . 80'lerin başında, David Korn Bourne kabuğu için birkaç uzantı yazdı, birkaç hatayı düzeltti ve gariplikleri tasarladı (ve bazılarını tanıttı) ve buna Korn kabuğu adını verdi.

90'lı yılların başlarında POSIX, sh dili Korn kabuğunun bir alt kümesine göre belirledi ve çoğu sistem şimdi bunları /bin/shKorn kabuğuna veya bu spesifikasyona uygun bir kabuğa değiştirdi. BSD'ler söz konusu olduğunda /bin/sh, başlangıçta (Bourne kabuğunu lisans nedenleriyle artık kullanamadıktan sonra), Bourne kabuğunun bir klonu olan ksh uzantılarına sahip bir klon olan Almquist kabuğunu yavaş yavaş değiştirdiler ve POSIX uyumlu oldu.

Bugün, tüm POSIX sistemleri çoğunlukla POSIX uyumlu olan bir kabuğa sahiptir sh(çoğunlukla, ancak zorunlu olarak /bin, POSIX belirttiği yardımcı programların yolunu belirtmez). Genellikle ksh88, ksh93, pdksh, bash, ash veya zsh²'ye dayanır, ancak Bourne kabuğu asla POSIX uyumlu olmadığından Bourne kabuğu değil³. Bu kabukların birkaç ( bash, zsh, yashve bazı pdksholarak çağrıldığında türevleri, POSIX uyumlu modu etkinleştirmek shve vardır daha başka şekilde uyumlu).

bash(Korn kabuğuna yapılan GNU cevabı) aslında tek açık kaynak kabuğudur (ve şu anda sadece diğeri genellikle 90'lardan beri yeni bir özellik kazanmamış olan ksh88'e dayandığı için korunabilir) POSIX uyumlu olması sh(macOS sertifikasının bir parçası olarak).

#! /bin/sh -She-bang ile bir komut dosyası yazdığınızda , standart bir shsözdizimi kullanmalısınız (ve taşınabilir olmak istiyorsanız bu komut dosyasında kullanılan yardımcı programlar için standart sözdizimi de kullanmalısınız, yalnızca bir kabuk yorumlanırken kabuk değil komut dosyası) kullanırsanız, o standart shsözdizimi yorumlayıcısının hangi uygulamasının kullanıldığı önemli değildir ( ksh, bash...).

Bu mermileri kullanmadığınız sürece standardın üzerinde uzantılara sahip olması önemli değil. Standart C kodu yazdığınızda ve bir derleyicinin (örneğin gcc) veya diğerinin uzantılarını kullanmadığınız sürece, C kodu yazmak gibidir , derleyicinin uyumlu olması koşuluyla derleyici uygulamasından bağımsız olarak kodunuz derlenmelidir.

İşte, birlikte #! /bin/shdişi patlamayla, sizin asıl sorun sistem olacağını /bin/shBourne kabuğu olduğunu örneği gibi standart özellikleri desteklemiyor için $((1+1)), $(cmd), ${var#pattern}... sen alternatif çözüm gibi gerekebilir durumda:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

Bu arada, Ubuntu varsayılan /bin/sholarak değil bash. Bu var dashbugünlerde, NetBSD dayalı bir kabuk shçoğunlukla çok baytlık karakterleri desteklemez dışında POSIX uyumludur Almquist kabuğu dayalı kendisi. Ubuntu ve diğer Debian tabanlı sistemlerde, arasında seçim yapabilirsiniz bashve dashiçin /bin/shbirlikte dpkg-reconfigure dash) 4 . shDebian ile gönderilen komut dosyaları, Debian politika standardına (POSIX standardının bir üst kümesi) yazıldıkları her iki kabukta da aynı şekilde çalışmalıdır. Muhtemelen çalışma Tamam da onlar bulacaksınız zshbireyin shöykünme veya bosh(muhtemelen ksh93ne de yashbir bizde olmayan localDebian politikası değil POSIX) tarafından gerekli yerleşiği ().

Unix.stackexchange.com adresindeki tüm sistemlerde bir POSIX vardır sh . Çoğu ( /bin/shbir /bindizini olmayan çok nadir bulunanları bulabilirsiniz, ancak muhtemelen bunu umursamıyorsunuz) ve bu genellikle bir POSIX shyorumlayıcısı (ve nadir durumlarda bunun yerine (standart olmayan) bir Bourne kabuğu ).

Ancak sh, bir sistemde bulabileceğinizden emin olabileceğiniz tek kabuk yorumlayıcısıdır. Diğer mermiler için macOS, Cygwin ve çoğu GNU / Linux dağıtımının olacağından emin olabilirsiniz bash. SYSV türevi işletim sistemlerinde (Solaris, AIX ...) genellikle ksh88, muhtemelen ksh93 olacaktır. OpenBSD, MirOS'un bir pdksh türevi olacaktır. macOS sahip olacak zsh. Ama bundan, hiçbir garanti olmayacak. bashBu diğer mermilerin /binya da başka bir yere monte edilip edilmeyeceğine veya herhangi bir yere monte edileceğine dair bir garanti yoktur ( /usr/local/binörneğin, monte edildiğinde genellikle BSD'lerde bulunur). Ve elbette kurulacak olan kabuğun versiyonunun garantisi yok.

Bunun #! /path/to/executablebir kural olmadığını unutmayın , tüm Unix benzeri çekirdeklerin ( Dennis Ritchie tarafından 80'lerin başında tanıtıldı ), ilk satırda yorumlayıcının yolunu belirterek keyfi dosyaların yürütülmesine izin veren bir özelliktir #!. Herhangi bir yürütülebilir olabilir.

Kimin ilk satırı başlar bir dosyayı çalıştırdığınızda #! /some/file some-optional-arg, çekirdek yürütme biter /some/fileile some-optional-argsenaryonun yolu ve argümanlar gibi orijinal argümanlar. Ne olduğunu #! /bin/echo testgörmek için ilk satırı yapabilirsiniz :

$ ./myscript foo
test ./myscript foo

Kullandığınızda /bin/sh -yerine /bin/echo testçekirdek çalıştırır, /bin/sh - ./myscript foo, shiçerik saklanan kodunu yorumlar myscriptbir yorum (başlar beraber olarak ve göz ardı eder İlk satır #).


Today Muhtemelen bugün herhangi birimizin /bin/shBourne kabuğuna dayanan bir sistemle karşılaşacağı tek sistem Solaris 10'dur. Solaris, Bourne kabuğunu geriye dönük uyumluluk için orada tutmaya karar veren birkaç Unice'den biridir (POSIX shdili tam değildir. Bourne kabuğuyla geriye dönük uyumlu) ve (en azından masaüstü ve tam sunucu dağıtımları için) shbaşka bir yerde /usr/xpg4/bin/shPOSIX'e sahiptir ( ksh88'e dayalı olarak), ancak /bin/shşu anda ksh93 olan Solaris 11'de değişmiştir . Diğerleri çoğunlukla geçersizdir.

² eskiden MacOS / X , ancak daha sonra değiştirildi . POSIX uygulaması olarak kullanılmak birincil odak noktası değildir . Onun mod embed veya çağrı (edebilmek için öncelikle ) POSIX kod komut/bin/shzshbashzshshshsourceshzsh

³ Son zamanlarda, @schily , POSIX uyumlu olmak için OpenSolaris kabuğunu (Bourne kabuğuna dayanan SVR4 kabuğundaki taban) çağırdı, boshancak henüz herhangi bir sistemde kullanıldığının farkında değilim. Bununla birlikte ksh88, Bourne kabuğunun koduna dayanan ikinci bir POSIX uyumlu kabuk yapar

4 Daha eski sürümlerde mkshveya POSIX lkshenkarnasyonunu da kullanabilirsiniz . Bu, Forsyth kabuğuna (Bourne kabuğunun başka bir yeniden uygulaması) dayanan pdksh'ye dayanan MirOS (eski adıyla MirBSD) kabuğudır)


Küçük şey (cevap ortası kabuk kodu hakkında): exec sh "$0" "$@"ayarladıktan hemen sonra kullanmamalısınız PATH? Bunun shdoğru yerden alması gerekirdi, diye düşünürdüm.
Kusalananda

1
@Kusalananda, bu çalışmalı ama bir şeylerin yanlış olması durumunda sonsuz bir döngüye girebileceğimiz için daha risklidir (yanlış izinlere sahip sh, getconf değiştirildi ...). Her neyse, geri kalanı Solaris 10'a özgüdür, bu yüzden içeriği de dahil olmak üzere her şeyi kodlayabiliriz $PATH.
Stéphane Chazelas

POSIX kabuğu olarak ksh kullanan OSX için yapılan tüm alıntılar. Varsayılan kabuğu tcsh idi, ancak özellikle Korn Shell'in OSX çıkana kadar açık kaynak olmadığı için
bash'ın

1
@ Mark, OSX'in ksh kullandığını söylemedim. Ben eskiden zsh olduğunu söylediler ve bash (özel bir bash yapı) geçti.
Stéphane Chazelas

1
@fpmurphy, önceki sürümlere bakarsanız, bash ksh ile Bourne kabuğuyla uyumlu olmayan her yerde ksh ile siding yapıyordu. Ksh88 ile aynı özellik düzeyine ulaşmak için bash2'ye kadar beklemek zorunda kalırken, bash başlangıçta zaten emshs $(...)/ vi modları, tilde / brace genişletmeleri (başlangıçta csh'den olanlar), fc, dizgi, takma ad gibi birkaç ksh uzantısına sahipti. , ksh tarzı işlev sözdizimi ...
Stéphane Chazelas

8

Evet #!/bin/shbir komut dosyasında kullanabilirsiniz , çünkü /bin/sh(umarım) bu tür sistemlerde, genellikle bir bashdavranış gibi (az ya da çok) davranan bir tür bağlantı yoluyla sağlanır sh. Örneğin, aşağıdakilere bağlantı shveren bir Centos7 sistemi bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Ayrıca kullanabilirsiniz #!/bin/bashEğer bir yazıyorsanız eğer bashsadece o sistem için senaryo ve kullanmak istediğiniz bashözellikleri. Ancak, bu tür komut OpenBSD'de örneğin taşınabilirlik sorunları yaşayacaktır bashyönetici yüklemek için sorun sürerse, sadece yüklenir (I do not) ve daha sonra yüklenir /usr/local/bin/bashdeğil /bin/bash. Kesinlikle POSIX #!/bin/shbetiği daha taşınabilir olmalıdır.


Şuna dikkat edin: "Olarak çağrıldığında sh, Bash başlangıç ​​dosyalarını okuduktan sonra POSIX moduna girer." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman

2
İşimde RHEL sunucuları için komut dosyaları yazarken, #!/bin/bashPOSIX dışı özelliklerden yararlanabilmek için tam olarak kullanıyorum .
Monty Harder

@MontyHarder IIRC RHEL üzerinde /bin/shbir sembolik bağlantı bash, doğru mu? Ben kesinlikle CentOS biliyorum.
Sergiy Kolodyazhnyy

1
@SergiyKolodyazhnyy Evet, az önce kontrol ettiğim RHEL sunucusunda bir sembol bağlantısı bash. İkili, onu çağırmak için hangi adın kullanıldığını bilir ve çağrıldığında sheski Bourne gibi davranır sh.
Monty Harder

6

Sen sordun

ubuntu dağıtımlarında yazılan kabuk komut dosyalarına #! / bin / sh yorumunu koymak doğru mudur?

Cevap, kabuk betiğine ne yazdığınıza bağlıdır.

  • Taşınabilir POSIX uyumlu komut dosyaları kullanıyorsanız ve bash'a özgü komutlar kullanmıyorsanız , kullanabilirsiniz /bin/sh.

  • Komut dosyasını yalnızca bash olan bir makinede kullandığınızı biliyorsanız ve bash'a özgü sözdizimini kullanmak istiyorsanız ,/bin/bash

  • Komut dosyasının bir dizi unix makinesi üzerinde çalışacağından emin olmak istiyorsanız , yalnızca POSIX uyumlu sözdizimi kullanmanız ve/bin/sh

  • Düzenli olarak kullandığınız takdirde başka kabuk (örn Ksh , zsh veya tcsh ) ve betiğinizde o sözdizimi kullanmak istiyorum, o zaman gereken uygun tercüman kullanmak (gibi /bin/ksh93, /bin/zshya da /bin/tcsh)


3

"#!" yorum her zaman /bin/bashveya kullanmaz /bin/sh. Yalnızca kabuk komut dosyaları için değil, yorumlayıcının ne olması gerektiğini de listeler. Örneğin benim python betiklerim genellikle ile başlar #!/usr/bin/env python.

Şimdi arasındaki fark #!/bin/shve #!/bin/basholmasıdır /bin/shhep bir sembolik değildir /bin/bash. Genellikle ama her zaman değil. Ubuntu burada dikkate değer bir istisnadır. Ben senaryo CentOS iyi çalışıyor gördüm ama Ubuntu üzerinde başarısız çünkü yazar ile bash özgü sözdizimi kullandı #!/bin/sh.


1

Tüm Unix sistemlerinde /bin/shmevcut olan tüm bu harika cevaplara biraz soğuk su döktüğüm için özür dilerim - tüm zamanların en çok kullanılan Unix sistemi hariç: Android.

Android'in kabuğu /system/bin/shvar ve genellikle /bin/shköklü bir sistemde bile bağlantı kurmanın bir yolu yok (sistemin selinux ve yetenekler (7) sınırlayıcı kümeler kullanılarak kilitlenmesi nedeniyle).

Android'in POSIX uyumlu olmadığını söyleyenler için: çoğu Linux ve BSD dağıtımı da değildir. Ve /bin/shbu yolla varlığı standart tarafından zorunlu değildir :

Uygulamalar standart unutmamalıdır PATHkabuğuna olduğu varsayılır edilemez ya /bin/shya /usr/bin/sh, ve sorgulanması belirlenmelidir PATHtarafından döndürülen getconf PATHdönen yol adı mutlak yol adı değil yerleşik bir kabuk olmasını sağlamak.


POSIX olmaya çalışın tüm sistemler (sertifikalı olanlar dahil) çok sayıda uygunluk hatalar uyumlu iken, Android (ve yönlendirici veya ampul OS gibi diğer birçok gömülü sistemler) yok niyetinde POSIX uyumlu olması. Android, POSIX arayüzüne geldiği durumlar dışında burada konu dışı.
Stéphane Chazelas

@Christopher, hangisi getconf? Mesela Solaris 11.4'te bu tek /usr/binmi olacaktı ? İçindeki /usr/xpg4/bin(SUSv2 uyumluluğu için), /usr/xpg6/binİçindeki (SUSv3 uyumu için)? /usr/xpg7/bin(SUSv4 için)?
Stéphane Chazelas

@ StéphaneChazelas, niyetleri değerlendirmek istiyorsak, sanırım bazı Linus Torvalds veya Theo de Raadt'ı POSIX hakkında çok fazla umursamadıkları etkiyi kolayca kazabilirim ;-) Ve çoğu gömülü sistem linux'a dayanıyor + busybox, tipik Unix benzeri sistemden daha az POSIX uyumlu. Ve a) android gerçekten bir "gömülü" sistem değildir ve b) bir android sistemi bir kabuk olmadan POSIX uyumlu hale getirilebilir/bin/sh
mosvy

1
@mosvy, söyledikleriniz çoğunlukla doğrudur. Ancak Torvalds sadece Linux çekirdeği için konuşabilir. Chet Ramey bash için POSIX uyumluluğunu önemser, RedHat POSIX uyumluluğunu önemser (Austin grubuna sponsor olurlar ve grup toplantılarına otururlar, bir çok GNU yazılımını muhafaza ederler). Fikir, POSIX'in çoğu Unix benzeri sistemin baktığı tek standart olmasıdır. Kullanıcılar, farklı sistemlere taşınabilir yazılımların bulunmasını kolaylaştırdığı için POSIX uyumludur. İdeal değil ama hiç yoktan iyidir. Android'in kendi programlama API'sı var, POSIX gerçekten endişe verici değil.
Stéphane Chazelas
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.