Genellikle Ubuntu LTS sunucularıyla çalışıyorum ki hangi sembolik bağ
/bin/sh
/bin/dash anlıyorum. Bir sürü dağıtım olsa da sembolik link
/bin/sh to
/bin/bash .
Bundan, bir komut dosyası üstte
#!/bin/sh kullanıyorsa, tüm sunucularda aynı şekilde çalışmayabileceğini anlıyor muyum?
Bu komut dosyaları sunucular arasında maksimum taşınabilirlik istendiğinde komut dosyaları için hangi kabuğun kullanılacağı konusunda önerilen bir uygulama var mı?
Kabuk komut dosyaları için kabaca dört taşınabilirlik seviyesi vardır (shebang hattı söz konusuysa):
En taşınabilir: Bir
#!/bin/sh shbang kullanın ve only POSIX standardında belirtilen temel kabuk sözdizimini kullanın. Bu hemen her POSIX / unix / linux sisteminde çalışmalıdır. (Aslında, eski miras Bourne kabuğuna sahip Solaris 10 ve önceki sürümleri, POSIX'i bu kadar uyumlu olmayan
/bin/sh olarak geçirmiştir.)
İkinci taşınabilirlik:
#!/bin/bash (veya
#!/usr/bin/env bash ) şabang hattı kullanın ve bash v3 özelliklerine sadık kalın. Bu bash (beklenen konumda) olan herhangi bir sistem üzerinde çalışacaktır.
Üçüncü en taşınabilirlik:
#!/bin/bash (veya
#!/usr/bin/env bash ) şabang hattı kullanın ve bash v4 özelliklerini kullanın. Bash v3'u olan herhangi bir sistemde başarısız olur (örn. Lisans nedenleriyle kullanmak zorunda olan macOS).
En az taşınabilir: Bir
#!/bin/sh shbang kullanın ve POSIX kabuğu sözdizimine bash uzantıları kullanın. Bu, / bin / sh için bash'dan farklı bir sistemi olan herhangi bir sistemde başarısız olur (son Ubuntu sürümleri gibi). Bunu hiç yapma sakın. Bu sadece bir uyumluluk sorunu değil, sadece yanlış yanlıştır. Ne yazık ki, bu birçok insanın yaptığı bir hatadır.
Tavsiyem: senaryo için ihtiyacın olan tüm kabuk özelliklerini sağlayan ilk üçün en muhafazakarını kullanın. Maksimum taşınabilirlik için seçenek # 1 kullanın, ancak deneyimlerimde bazı bash özellikleri (diziler gibi) # 2 ile birlikte kullanacağım kadar yardımcı olur.
Yapabileceğiniz en kötü şey # 4, yanlış şaban kullanarak. Temel POSIX özellikleri ve hangilerinin bash uzantıları olduğundan emin değilseniz, bash shebang (seçenek # 2) ile sopa atın veya komut dosyasını çok temel bir kabukla (Ubuntu LTS sunucularınızdaki çizgi gibi) iyice test edin. Ubuntu wiki'nin dikkat etmesi gereken iyi bir bashism listesi var .
Ayrıca, kabuğun farklı sistemler arasında farklı olan tek şey olmadığını da unutmayın; Linux'a alıştıysanız, diğer unix sistemlerinde (örneğin, bsd, macOS) bulamayabileceğiniz çok sayıda standart dışı uzantıya sahip olan GNU komutlarına alıştınız. Maalesef burada basit bir kural yok, yalnızca kullandığınız komutların varyasyon aralığını bilmeniz gerekiyor.
Taşınabilirlik bakımından en iğrenç komutlardan biri en temel özelliklerden biridir:
echo . Herhangi bir seçenekle (
echo -n veya
echo -e ) herhangi bir zaman kullanırsanız veya dizeye yazdırmak için herhangi bir kaçış (ters eğik çizgi) ile farklı sürümler farklı şeyler yapacaktır. Ardından bir satır besleme olmadan bir dize yazdırmak istediğinizde veya dizedeki kaçışlarla yazdırmak istediğinizde bunun yerine
printf kullanın (ve nasıl çalıştığını öğrenin -
echo daha karmaşıktır).
ps komutu da karışıklıktır .
İzlenecek diğer bir genel şey, son / GNUish'in komut seçeneği sözdizimine uzantılarıdır: eski (standart) komut biçimi, komutun seçeneklerle (tek çizgi ile ve her seçenek tek bir harfle) ardından gelmesinin ardından Komut argümanları. Yakın zamandaki (ve çoğu kez taşınabilir olmayan) türevler, seçeneklerin argümanlardan sonra gelmesine izin veren ve seçenekleri argümanlardan ayırmak için
-- kullanarak uzun seçenekler (genellikle
-- ile birlikte verilir) içerir.
Yapı için TXR dilini hazırlayan
./configure komut dosyasında daha taşınabilirlik için aşağıdaki önsözü yazmıştım.
#!/bin/sh , POSIX uyumlu olmayan eski bir Bourne Kabuğu olsaydı bile betik kendini önyükleyecektir. (Her sürümü bir Solaris 10 VM üzerine inşa ediyorum).
#!/bin/sh # use your own variable name instead of txr_shell; # adjust to taste: search for your favorite shells if test x$txr_shell = x ; then for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do if test -x $shell ; then txr_shell=$shell break fi done if test x$txr_shell = x ; then echo "No known POSIX shell found: falling back on /bin/sh, which may not work" txr_shell=/bin/sh fi export txr_shell exec $txr_shell $0 ${@+"$@"} fi # rest of the script here, executing in upgraded shell
Buradaki fikir, altında çalıştığımızdan daha iyi bir kabuk bulmamız ve bu kabuğu kullanarak komut dosyasını yeniden çalıştırmamızdır.
txr_shell çevre değişkeni ayarlanır; böylece, yeniden çalıştırılan komut dosyası yeniden yinelenen tekrarlanan örneğini bilir.
(Benim
txr_shell ,
txr_shell değişkeni tam olarak iki amaca yönelik olarak da kullanılır: öncelikle betiğin çıktısında bilgilendirici bir mesajın bir parçası olarak basılmıştır.İkincisi,
Makefile
SHELL değişkeni olarak kurulur, böylece
make bu kabuğu tarifleri yürütmek
make de kullanacaktır.)
/bin/sh çizgi olduğu bir sistemde, yukarıdaki mantığın
/bin/bash dosyasını bulacağını ve betiği bununla yeniden çalıştıracağını görebilirsiniz.
Bir Solaris 10 kutusunda, Bash bulunursa,
/usr/xpg4/bin/sh başlatılacaktır.
Önsöz, varoluş testleri için
test ve bazı kırık eski kabukları ikram etmek için argümanları genişletmek için
${@+"$@"} hükmü kullanarak muhafazakar bir kabuk lehçesinde yazılmıştır (eğer varsa
"$@" olurdu) POSIX uyumlu bir kabukta).
Bourne kabuk dilinin tüm çeşitleri, Perl, Python, Ruby, node.js ve hatta (tartışmasız) Tcl gibi modern komut dosyası dillerine kıyasla objektif olarak korkunçtur. Hatta biraz karmaşık bir şey yapmak zorunda kalırsanız, kabuk komut dosyası yerine yukarıdakilerden birini kullanırsanız, uzun vadede daha mutlu olacaksınız.
Kabuk dilinin hâlâ yeni dillere kıyasla sahip olduğu tek avantaj, kendisini
/bin/sh olarak adlandıran bir şeyin Unix olduğunu ileri sürülen herhangi bir şey üzerinde olması garantisi olmasıdır. Bununla birlikte, bir şey bile POSIX uyumlu olmayabilir; Eski tescilli Unix'lerin birçoğu Unix95'in talep ettiği değişikliklerden prior (evet, Unix95, yirmi yıl önce ve sayım yaparak)
/bin/sh ve yardımcı programların uyguladığı dili dondurdu. Şanslıysanız Unix95 veya POSIX.1-2001 setleri olabilir, varsayılan PATH (örneğin
/usr/xpg4/bin ) değil bir dizinde bulunan araçlar ancak bunların var olması garanti edilmez.
Bununla birlikte, Perl'in temelleri, Bash'den çok keyfi olarak seçilmiş bir Unix kurulumunda more likely . ("Perl'in temelleri" ile
/usr/bin/perl ve Perl 5'in some eski, muhtemelen eski versiyonudur ve şanslıysanız tercümanın bu versiyonuyla birlikte gönderilen modüller seti de mevcut.)
Bu nedenle:
Unix olduğunu düşündüğünüz everywhere ("configure" komut dosyası gibi) bir şeyler yazıyorsanız,
#! /bin/sh
#! /bin/sh kullanıyorsanız ve herhangi bir uzantı kullanmamalısınız. Günümüzde bu durumda POSIX.1-2001 uyumlu kabuk yazardım, ancak birisi paslı demir desteği istediğinde POSIX'leri düzeltmeye hazır olacağım.
Ancak, her yerde çalışması gereken bir şey yazmıyorsanız, herhangi bir Başsyizliği kullanmak için cazip olduğunuz andan itibaren, her şeyi yerine daha iyi bir betik dili ile yeniden yazmalısınız. Gelecekteki benliğiniz sana teşekkür edecek.
(Bash uzantılarını kullanmak ne zaman uygundur? Birinci mertebeye asla: ikinci derecede: yalnızca Bash etkileşimli ortamını genişletmek için - örneğin akıllı sekme tamamlama ve fantezi komut istemleri sağlamak için.)