#! / bin / sh vs #! / bin / bash per la massima portabilità

cherouvim 07/30/2017. 3 answers, 2.886 views
linux bash shell sh

Di solito lavoro con i server LTS di Ubuntu, da quello che capisco symlink /bin/sh a /bin/dash . Molte altre distribuzioni tramite symlink /bin/sh a /bin/bash .

Da quello capisco che se uno script usa #!/bin/sh in cima potrebbe non funzionare allo stesso modo su tutti i server?

Esiste una pratica suggerita su quale shell utilizzare per gli script quando si desidera la massima portabilità di tali script tra i server?

1 Comments
Thorbjørn Ravn Andersen 08/01/2017
Ci sono lievi differenze tra i vari gusci. Se la portabilità è la più importante per te allora usa #!/bin/sh e non usare nient'altro che quello fornito dalla shell originale.

3 Answers


Gordon Davisson 08/01/2017.

Ci sono circa quattro livelli di portabilità per gli script di shell (per quanto riguarda la linea shebang):

  1. Più portatile: usa un #!/bin/sh shebang e usa only la sintassi di shell di base specificata nello standard POSIX . Questo dovrebbe funzionare praticamente su qualsiasi sistema POSIX / unix / linux. (Bene, tranne Solaris 10 e precedenti che avevano la vera shell legacy Bourne, prima di POSIX così non conforme, come /bin/sh .)

  2. La seconda più portabile: usa una riga #!/bin/bash (o #!/usr/bin/env bash ) e rimani fedele alle caratteristiche di bash v3. Funzionerà su qualsiasi sistema che abbia bash (nella posizione prevista).

  3. Terzo più portabile: usa la linea shebang #!/bin/bash (o #!/usr/bin/env bash ) e usa le funzioni di bash v4. Questo fallirà su qualsiasi sistema che abbia bash v3 (ad es. MacOS, che deve usarlo per motivi di licenza).

  4. Meno portatile: usa un #!/bin/sh shebang e usa le estensioni bash per la sintassi della shell POSIX. Ciò fallirà su qualsiasi sistema che abbia qualcosa di diverso da bash per / bin / sh (come le recenti versioni di Ubuntu). Non farlo mai; non è solo un problema di compatibilità, è semplicemente sbagliato. Sfortunatamente, è un errore che fanno molte persone.

La mia raccomandazione: usa il più conservatore dei primi tre che fornisce tutte le funzionalità della shell necessarie per lo script. Per la massima portabilità, usa l'opzione n. 1, ma nella mia esperienza alcune funzioni di bash (come gli array) sono abbastanza utili che andrò con # 2.

La cosa peggiore che puoi fare è la # 4, usando la shebang sbagliata. Se non sei sicuro di quali funzionalità siano POSIX di base e quali siano le bash, puoi utilizzare uno script bash (ad esempio l'opzione n. 2) oppure testare lo script con una shell molto semplice (come un trattino sui tuoi server Ubuntu LTS). Il wiki di Ubuntu ha una buona lista di bashismi a cui prestare attenzione .

Ci sono alcune ottime informazioni sulla storia e le differenze tra le shell nella domanda Unix e Linux "Cosa significa essere sh-compatibili?" e la domanda Stackoverflow "Differenza tra sh e bash" .

Inoltre, sii consapevole che la shell non è l'unica cosa che differisce tra i diversi sistemi; se sei abituato a Linux, sei abituato ai comandi GNU, che hanno un sacco di estensioni non standard che potresti non trovare su altri sistemi Unix (es. bsd, macOS). Sfortunatamente, non c'è una regola semplice qui, devi solo conoscere l'intervallo di variazione per i comandi che stai utilizzando.

Uno dei comandi più cattivi in ​​termini di portabilità è uno dei più basilari: l' echo . Ogni volta che lo usi con qualsiasi opzione (es. echo -n o echo -e ), o con qualsiasi escape (backslash) nella stringa da stampare, diverse versioni faranno cose diverse. Ogni volta che vuoi stampare una stringa senza un linefeed, o con gli escape nella stringa, usa invece printf (e scopri come funziona - è più complicato di echo ). Il comando ps è anche un casino .

Un'altra cosa generale da tenere in considerazione è l'estensione recente / GNUish per il comando della sintassi dell'opzione: il vecchio formato di comando (standard) è che il comando è seguito da opzioni (con un singolo trattino e ciascuna opzione è una singola lettera), seguita da argomenti di comando. Le varianti recenti (e spesso non portatili) includono le opzioni lunghe (generalmente introdotte con -- ), che consentono alle opzioni di venire dopo gli argomenti e di utilizzare -- per separare le opzioni dagli argomenti.

5 comments
12 pabouk 07/30/2017
La quarta opzione è semplicemente un'idea sbagliata. Per favore non usarlo.
3 Gordon Davisson 07/30/2017
@pabouk Sono completamente d'accordo, quindi ho modificato la mia risposta per renderla più chiara.
1 jlliagre 07/30/2017
La tua prima affermazione è leggermente fuorviante. Lo standard POSIX non specifica nulla riguardo allo shebang al di fuori dicendo che usarlo porta a un comportamento non specificato. Inoltre, POSIX non specifica dove deve essere localizzata la shell posix, solo il suo nome ( sh ), quindi non è garantito che il percorso corretto sia /bin/sh . Il più portabile è quindi non specificare alcuno shebang o adattare lo shebang al sistema operativo utilizzato.
2 Michael Kjörling 07/30/2017
Sono caduto in # 4 con una mia sceneggiatura di recente, e non riuscivo proprio a capire perché non funzionasse; dopotutto, gli stessi comandi hanno funzionato in modo solido e hanno fatto esattamente ciò che volevo che facessero, quando li ho provati direttamente nella shell. Non appena ho cambiato #!/bin/sh in #!/bin/bash , lo script ha funzionato perfettamente. (A mia difesa, quella sceneggiatura si era evoluta nel tempo da una che aveva solo bisogno di sh-isms, a una che si basava su un comportamento bash.)
2 jlliagre 07/30/2017
@ MichaelKjling La (vera) shell Bourne non è quasi mai associata alle distribuzioni Linux e comunque non è conforme a POSIX. La shell standard POSIX è stata creata dal comportamento di ksh , non da Bourne. La maggior parte delle distribuzioni Linux che seguono il FHS sta avendo /bin/sh come un collegamento simbolico alla shell che scelgono di fornire la compatibilità POSIX, di solito bash o dash .

Kaz 07/31/2017.

Nello script ./configure che prepara il linguaggio TXR per la creazione, ho scritto il seguente prologo per una migliore portabilità. Lo script si avvierà automaticamente anche se #!/bin/sh è una vecchia Bourne Shell non conforme a POSIX. (Costruisco ogni versione su una macchina virtuale 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 ${@+"$@"}
fi

# rest of the script here, executing in upgraded shell 

L'idea qui è che troviamo una shell migliore di quella in cui stiamo lavorando, e ri-eseguiamo lo script usando quella shell. La variabile di ambiente txr_shell è impostata, in modo che lo script rieseguito sappia che è l'istanza ricorsiva rieseguita.

(Nel mio script, anche la variabile txr_shell viene successivamente utilizzata, per esattamente due scopi: in primo luogo viene stampata come parte di un messaggio informativo nell'output dello script. In secondo luogo, viene installata come variabile SHELL nel Makefile , in modo che make userà questa shell anche per eseguire le ricette.)

Su un sistema in cui /bin/sh è dash, è possibile vedere che la logica sopra troverà /bin/bash e rieseguirà lo script con quello.

Su una casella di Solaris 10, /usr/xpg4/bin/sh eseguirà il kick se non viene trovato Bash.

Il prologo è scritto in un dialetto conservativo, usando test per i test di esistenza dei file, e il trucco ${@+"$@"} per l'espansione degli argomenti relativi a alcune vecchie shell (che sarebbero semplicemente "$@" se fossimo in una shell conforme a POSIX).

2 comments
Charles Duffy 07/31/2017
Uno non avrebbe bisogno dello x hacker se fossero state usate le citazioni appropriate, dal momento che le situazioni che imponevano quell'idioma circonda ora invocazioni di test deprecate con -a o -o combinando più test.
Kaz 07/31/2017
@CharlesDuffy Infatti; il test x$whatever io stia perpetrando lì sembra una cipolla nella vernice. Se non possiamo fidarci della vecchia shell rotta per fare quoting, allora il tentativo ${@+"$@"} è inutile.

zwol 07/31/2017.

Tutte le varianti del linguaggio shell Bourne sono oggettivamente terribili rispetto ai moderni linguaggi di scripting come Perl, Python, Ruby, node.js e persino (discutibilmente) Tcl. Se devi fare qualcosa anche solo un po 'complicato, sarai più felice nel lungo periodo se utilizzi uno dei suddetti invece di uno script di shell.

L'unico vantaggio che il linguaggio della shell ha ancora su quei linguaggi più recenti è che something che si chiama se stesso /bin/sh è garantito che esista su qualsiasi cosa che pretende di essere Unix. Tuttavia, qualcosa potrebbe non essere nemmeno conforme a POSIX; molti dei legacy Unix proprietari legavano il linguaggio implementato da /bin/sh e le utilità nel PATH predefinito prior delle modifiche richieste da Unix95 (sì, Unix95, venti anni fa e conteggio). Potrebbe esserci un insieme di Unix95, o anche POSIX.1-2001 se si è fortunati, strumenti in una directory not sul PATH predefinito (es /usr/xpg4/bin ) ma non è garantito che esistano.

Tuttavia, le basi di Perl hanno more likely di essere presenti su un'installazione Unix arbitrariamente selezionata rispetto a Bash. (Per "le basi di Perl" intendo /usr/bin/perl esiste ed è some , forse piuttosto vecchia, di Perl 5, e se sei fortunato, anche il set di moduli fornito con quella versione dell'interprete è a disposizione.)

Perciò:

Se stai scrivendo qualcosa che deve funzionare everywhere che pretende di essere Unix (come uno script "configure"), devi usare #! /bin/sh #! /bin/sh , e non è necessario utilizzare estensioni di alcun genere. Oggi scriverei shell POSIX.1-2001 in questa circostanza, ma sarei pronto a sistemare i POSIXismi se qualcuno chiedesse supporto per il ferro arrugginito.

Ma se non stai scrivendo qualcosa che deve funzionare ovunque, allora nel momento in cui sei tentato di usare qualsiasi Bashism, dovresti invece fermare e riscrivere l'intera cosa in un linguaggio di scripting migliore. Il tuo sé futuro ti ringrazierà.

(Quindi quando is appropriato usare le estensioni di Bash? Al primo ordine: mai. Al secondo ordine: solo per estendere l'ambiente interattivo Bash, ad esempio per fornire smart tab-completion e prompt di fantasia.)


HighResolutionMusic.com - Download Hi-Res Songs

1 (G)I-DLE

POP/STARS flac

(G)I-DLE. 2018. Writer: Riot Music Team;Harloe.
2 Ariana Grande

​Thank U, Next flac

Ariana Grande. 2018. Writer: Crazy Mike;Scootie;Victoria Monét;Tayla Parx;TBHits;Ariana Grande.
3 Imagine Dragons

Bad Liar flac

Imagine Dragons. 2018. Writer: Jorgen Odegard;Daniel Platzman;Ben McKee;Wayne Sermon;Aja Volkman;Dan Reynolds.
4 Backstreet Boys

Chances flac

Backstreet Boys. 2018.
5 Clean Bandit

Baby flac

Clean Bandit. 2018. Writer: Jack Patterson;Kamille;Jason Evigan;Matthew Knott;Marina;Luis Fonsi.
6 BTS

Waste It On Me flac

BTS. 2018. Writer: Steve Aoki;Jeff Halavacs;Ryan Ogren;Michael Gazzo;Nate Cyphert;Sean Foreman;RM.
7 BlackPink

Kiss And Make Up flac

BlackPink. 2018. Writer: Soke;Kny Factory;Billboard;Chelcee Grimes;Teddy Park;Marc Vincent;Dua Lipa.
8 Lady Gaga

I'll Never Love Again flac

Lady Gaga. 2018. Writer: Benjamin Rice;Lady Gaga.
9 Kelly Clarkson

Never Enough flac

Kelly Clarkson. 2018. Writer: Benj Pasek;Justin Paul.
10 Fitz And The Tantrums

HandClap flac

Fitz And The Tantrums. 2017. Writer: Fitz And The Tantrums;Eric Frederic;Sam Hollander.
11 Little Mix

Told You So flac

Little Mix. 2018. Writer: Eyelar;MNEK;Raye.
12 Halsey

Without Me flac

Halsey. 2018. Writer: Halsey;Delacey;Louis Bell;Amy Allen;Justin Timberlake;Timbaland;Scott Storch.
13 Cher Lloyd

None Of My Business flac

Cher Lloyd. 2018. Writer: ​iamBADDLUCK;Alexsej Vlasenko;Kate Morgan;Henrik Meinke;Jonas Kalisch;Jeremy Chacon.
14 Bradley Cooper

Always Remember Us This Way flac

Bradley Cooper. 2018. Writer: Lady Gaga;Dave Cobb.
15 Calum Scott

No Matter What flac

Calum Scott. 2018. Writer: Toby Gad;Calum Scott.
16 Ashley Tisdale

Voices In My Head flac

Ashley Tisdale. 2018. Writer: John Feldmann;Ashley Tisdale.
17 Imagine Dragons

Machine flac

Imagine Dragons. 2018. Writer: Wayne Sermon;Daniel Platzman;Dan Reynolds;Ben McKee;Alex Da Kid.
18 Diplo

Close To Me flac

Diplo. 2018. Writer: Ellie Goulding;Savan Kotecha;Peter Svensson;Ilya;Swae Lee;Diplo.
19 Billie Eilish

When The Party's Over flac

Billie Eilish. 2018. Writer: Billie Eilish;FINNEAS.
20 Little Mix

Woman Like Me flac

Little Mix. 2018. Writer: Nicki Minaj;Steve Mac;Ed Sheeran;Jess Glynne.

Related questions

Hot questions

Language

Popular Tags