GNU/Linux >> Znalost Linux >  >> Linux

#!/bin/sh vs #!/bin/bash pro maximální přenositelnost

Řešení 1:

Existují zhruba čtyři úrovně přenositelnosti skriptů shellu (pokud jde o řádek shebang):

  1. Nejpřenosnější:použijte #!/bin/sh shebang a použijte pouze základní syntaxe shellu specifikovaná ve standardu POSIX. To by mělo fungovat v podstatě na jakémkoli systému POSIX/unix/linux. (No, kromě Solaris 10 a dřívějších, který měl skutečný původní Bourne shell, starší než POSIX tak nevyhovující, jako /bin/sh .)

  2. Druhý nejpřenosnější:použijte #!/bin/bash (nebo #!/usr/bin/env bash ) line shebang a držte se funkcí bash v3. Toto bude fungovat na jakémkoli systému, který má bash (v očekávaném umístění).

  3. Třetí nejpřenosnější:použijte #!/bin/bash (nebo #!/usr/bin/env bash ) line shebang a používejte funkce bash v4. Toto selže na jakémkoli systému, který má bash v3 (např. macOS, který jej musí používat z licenčních důvodů).

  4. Nejméně přenosné:použijte #!/bin/sh shebang a použijte rozšíření bash k syntaxi shellu POSIX. Toto selže na jakémkoli systému, který má něco jiného než bash pro /bin/sh (jako jsou nedávné verze Ubuntu). Nikdy to nedělejte; není to jen problém s kompatibilitou, je to prostě špatně. Bohužel je to chyba, kterou dělá mnoho lidí.

Moje doporučení:použijte nejkonzervativnější z prvních tří, který poskytuje všechny funkce shellu, které potřebujete pro skript. Pro maximální přenositelnost použijte možnost #1, ale podle mých zkušeností jsou některé funkce bash (jako pole) natolik užitečné, že půjdu s #2.

Nejhorší věc, kterou můžete udělat, je číslo 4, když použijete nesprávný shebang. Pokud si nejste jisti, které funkce jsou základní POSIX a které jsou bash rozšíření, buď zůstaňte u bash shebang (tj. možnost #2), nebo skript důkladně otestujte s velmi jednoduchým shellem (jako je pomlčka na vašich serverech Ubuntu LTS). Wiki Ubuntu má dobrý seznam bashismů, na které je třeba si dát pozor.

Existuje několik velmi dobrých informací o historii a rozdílech mezi shelly v otázce Unix &Linux "Co to znamená být kompatibilní?" a otázka Stackoverflow "Rozdíl mezi sh a bash".

Uvědomte si také, že shell není jediná věc, která se mezi různými systémy liší; pokud jste zvyklí na linux, jste zvyklí na příkazy GNU, které mají spoustu nestandardních rozšíření, která možná nenajdete na jiných unixových systémech (např. bsd, macOS). Bohužel zde neexistuje žádné jednoduché pravidlo, stačí znát rozsah variací příkazů, které používáte.

Jeden z nejhorších příkazů z hlediska přenositelnosti je jeden z nejzákladnějších:echo . Kdykoli jej použijete s libovolnými možnostmi (např. echo -n nebo echo -e ), nebo s libovolnými úniky (zpětnými lomítky) v řetězci k tisku, různé verze budou dělat různé věci. Kdykoli chcete vytisknout řetězec bez odřádkování za ním nebo s escapemi v řetězci, použijte printf místo toho (a zjistěte, jak to funguje – je to složitější než echo je). ps příkaz je také nepořádek.

Další obecnou věcí, kterou je třeba sledovat, jsou nedávná/GNUish rozšíření syntaxe volby příkazu:starý (standardní) formát příkazu je takový, že za příkazem následují volby (s jednou pomlčkou a každá volba je jedno písmeno), za nimi následuje příkazové argumenty. Nejnovější (a často nepřenosné) varianty zahrnují dlouhé možnosti (obvykle uváděné s -- ), umožňující volby následovat za argumenty a použití -- k oddělení možností od argumentů.

Řešení 2:

V ./configure skript, který připravuje jazyk TXR pro sestavení, jsem pro lepší přenositelnost napsal následující prolog. Skript se zavede sám, i když je #!/bin/sh je starý Bourne Shell nevyhovující POSIX. (Každé vydání stavím na virtuálním počítači Solaris 10).

#!/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 ${@+"[email protected]"}
fi

# rest of the script here, executing in upgraded shell

Myšlenka je taková, že najdeme lepší shell než ten, pod kterým běžíme, a znovu spustíme skript pomocí tohoto shellu. txr_shell Proměnná prostředí je nastavena tak, aby znovu spuštěný skript věděl, že jde o znovu spuštěnou rekurzivní instanci.

(V mém skriptu txr_shell proměnná se také následně používá, a to přesně ke dvěma účelům:za prvé je vytištěna jako součást informativní zprávy ve výstupu skriptu. Za druhé, je nainstalován jako SHELL proměnná v Makefile , takže make použije tento shell také pro provádění receptů.)

V systému, kde je /bin/sh je pomlčka, můžete vidět, že výše uvedená logika najde /bin/bash a znovu spusťte skript s tím.

Na krabici Solaris 10 /usr/xpg4/bin/sh spustí se, pokud nebude nalezen žádný Bash.

Prolog je napsán v konzervativním shell dialektu s použitím test pro testy existence souboru a ${@+"[email protected]"} trik pro rozšíření argumentů, které slouží k některým rozbitým starým shellům (což by bylo jednoduše "[email protected]" kdybychom byli v shellu vyhovujícím POSIX).

Řešení 3:

Všechny varianty jazyka Bourne shellu jsou objektivně hrozné ve srovnání s moderními skriptovacími jazyky jako Perl, Python, Ruby, node.js a dokonce (pravděpodobně) Tcl. Pokud musíte udělat cokoli, byť jen trochu komplikovaného, ​​budete z dlouhodobého hlediska šťastnější, když místo shellového skriptu použijete jeden z výše uvedených.

Jediná a jediná výhoda, kterou jazyk shellu oproti těm novějším jazykům stále má, je to něco volá sám sebe /bin/sh je zaručeno, že existuje na čemkoli, co se vydává za Unix. To však nemusí být ani v souladu s POSIX; mnoho ze starších proprietárních Unixů zmrazilo jazyk implementovaný /bin/sh a nástroje ve výchozí PATH předchozí ke změnám požadovaným Unix95 (ano, Unix95, před dvaceti lety a stále přibývají). V adresáři může být sada nástrojů Unix95, nebo dokonce POSIX.1-2001, pokud budete mít štěstí, ne na výchozí PATH (např. /usr/xpg4/bin ), ale jejich existence není zaručena.

Základy Perlu jsou však pravděpodobnější být přítomen na libovolně vybrané unixové instalaci, než je Bash. (Tím „základy Perlu“ mám na mysli /usr/bin/perl existuje a je nějaký , možná docela stará, verze Perlu 5, a pokud budete mít štěstí, je k dispozici také sada modulů dodávaná s touto verzí interpretu.)

Proto:

Pokud píšete něco, co musí fungovat všude který se vydává za Unix (například skript "configure"), musíte použít #! /bin/sh a nemusíte používat žádná rozšíření. V dnešní době bych za těchto okolností napsal shell vyhovující POSIX.1-2001, ale byl bych připraven opravit POSIXismy, kdyby někdo požádal o podporu pro rezavé železo.

Ale pokud nejsi když píšete něco, co musí fungovat všude, pak ve chvíli, kdy jste v pokušení použít jakýkoli bashismus, měli byste přestat a místo toho to celé přepsat do lepšího skriptovacího jazyka. Vaše budoucí já vám poděkuje.

(Takže když je je vhodné používat rozšíření Bash? K první objednávce:nikdy. K druhému řádu:pouze rozšířit interaktivní prostředí Bash — např. poskytovat inteligentní doplňování karet a efektní výzvy.)


Linux
  1. /usr/bin Vs /usr/local/bin Na Linuxu?

  2. Jaký je rozdíl mezi /sbin/nologin a /bin/false?

  3. Proč /bin/sh ukazuje na /bin/dash a ne /bin/bash?

  1. Jaký je rozdíl mezi /bin/false a /sbin/nologin jako uživatelský shell nologin

  2. Nainstalujte binární soubory do /bin, /sbin, /usr/bin a /usr/sbin, interakce s --prefix a DESTDIR

  3. Jaký je rozdíl mezi #!/usr/bin/env bash a #!/usr/bin/bash?

  1. povolení odepřeno pro skladatele v /usr/local/bin/

  2. Rozdíl mezi /bin a /usr/bin

  3. Přesunutý obsah /bin do /usr/bin, je možné vrátit zpět?