#! / bin / sh vs #! / bin / bash maksimaalinen siirrettävyys

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

Työskentelen yleensä Ubuntu LTS -palvelinten kanssa, mikä ymmärtää symlink /bin/sh tiedostosta /bin/dash . Paljon muita distroja, vaikka symlink /bin/sh /bin/bash .

Tästä olen ymmärtänyt, että jos komentosarja käyttää #!/bin/sh päälle, se ei välttämättä toimi samalla tavalla kaikilla palvelimilla?

Onko olemassa ehdotettu käytäntö, johon shell käyttää skriptit, kun haluat maksimaalisen siirrettävyyden näiden skriptien välillä palvelimia?

1 Comments
Thorbjørn Ravn Andersen 08/01/2017
Eri kuorien välillä on pieniä eroja. Jos siirrettävyys on sinulle tärkeintä, käytä #!/bin/sh ja älä käytä mitään muuta kuin alkuperäinen kuori.

3 Answers


Gordon Davisson 08/01/2017.

Shell-komentosarjoilla on noin neljä tasoa siirrettävyys (siltä osin kuin kyseessä on shebang-linja):

  1. Useimmat kannettavat: käytä #!/bin/sh shebang ja käytä only POSIX-standardissa määriteltyä peruskuorisyntaksia . Tämän pitäisi toimia melko paljon POSIX / unix / linux -järjestelmällä. (No, paitsi Solaris 10 ja aiemmin, joilla oli todellinen Bourne-kuori, ennen kuin POSIX oli yhteensopiva, kuten /bin/sh ).

  2. Toiseksi kannettavin: käytä #!/bin/bash (tai #!/usr/bin/env bash ) shebang-linjaa ja pidä bash v3 -ominaisuuksissa. Tämä toimii millä tahansa järjestelmällä, jolla on bash (odotetulla sijainnilla).

  3. Kolmanneksi kannettavin: käytä #!/bin/bash (tai #!/usr/bin/env bash ) shebang-linjaa ja käytä bash v4 -ominaisuuksia. Tämä epäonnistuu millä tahansa järjestelmällä, jolla on bash v3 (esim. MacOS, jonka on käytettävä sitä lisensoinnin syistä).

  4. Vähiten kannettava: käytä #!/bin/sh shebang ja käytä bash-laajennuksia POSIX-kuori-syntaksille. Tämä epäonnistuu millä tahansa järjestelmällä, jolla on jotain muuta kuin bash / bin / sh (kuten viime Ubuntu-versiot). Älä koskaan tee tätä; se ei ole vain yhteensopivuusongelma, se on pelkkää vikaa. Valitettavasti se on virhe, jota monet ihmiset tekevät.

Oma suositus: käytä eniten varovaisia ​​kolmesta ensimmäisestä, joka toimittaa kaikki komentosarjan tarvitsemat kuoriominaisuudet. Saat maksimaalisen siirrettävyyden käyttämään vaihtoehtoa # 1, mutta kokemukseni mukaan jotkut bash-ominaisuudet (kuten taulukot) ovat tarpeeksi hyödyllisiä, että menen # 2: llä.

Pahin asia, jonka voit tehdä, on # 4, käyttäen väärää pääntiötä. Jos et ole varma, mitkä ominaisuudet ovat POSIX-perusosia ja jotka ovat bash-laajennuksia, joko jätä bash bash (eli vaihtoehto # 2) tai testata komentosarja perusteellisesti hyvin yksinkertaisella kuorella (kuten viiva Ubuntu LTS -palvelimissa). Ubuntun wikissä on hyvä lista bashismsista, joilla on varovaisuutta .

Jotkut erittäin hyvät tiedot Unix- ja Linux-kysymysten kuorien historiasta ja eroista "Mitä tarkoittaa yhteensopivuus?" ja Stackoverflow-kysymys "Sh: n ja bashin välinen ero" .

Huomaa myös, että kuori ei ole ainoa asia, joka eroaa eri järjestelmien välillä; jos olet tottunut Linuxiin, olet tottunut GNU-komentoihin, joilla on paljon epästandardeja laajennuksia, joita et löydä muilta Unix-järjestelmiltä (esim. bsd, macOS). Valitettavasti tässä ei ole yksinkertaista sääntöä, sinun tarvitsee vain tietää käyttämättömien komentojen vaihteluväli.

Yksi siirrettävyyden kannalta tärkeimmistä komennoista on yksi perusasioista: echo . Aina kun käytät sitä millä tahansa vaihtoehdolla (esim. echo -n tai echo -e ), tai tulosteiden merkkijono (backslashes), eri versiot tekevät erilaisia ​​asioita. Joka kerta, kun haluat tulostaa merkkijonoa ilman linjakonetta sen jälkeen, tai kun poistat merkkijonossa, käytä printf (ja opi, miten se toimii - se on monimutkaisempi kuin echo ). ps komento on myös sotku .

Toinen yleinen asia-to-watch-for on viimeisin / GNUish-laajennukset komento-option syntaksille: vanha (tavallinen) komentomuoto on se, että komentoa seuraa vaihtoehtoja (yhdellä viivalla ja jokainen vaihtoehto on yksittäinen kirjain), jota seuraa komento-argumentteja. Viimeaikaiset (ja usein ei-siirrettävät) versiot sisältävät pitkiä vaihtoehtoja (tavallisesti käyttöön -- ), jolloin vaihtoehdot tulevat argumenttien jälkeen ja käyttämällä -- eri vaihtoehtoja argumentteista.

5 comments
12 pabouk 07/30/2017
Neljäs vaihtoehto on vain väärä ajatus. Älä käytä sitä.
3 Gordon Davisson 07/30/2017
@pabouk Olen täysin samaa mieltä, joten muokkasin vastaukseni, jotta tämä olisi selkeämpi.
1 jlliagre 07/30/2017
Ensimmäinen lausunto on hieman harhaanjohtava. POSIX-standardi ei täsmennä mitään siitä, että shebang ei käytä sitä, mikä johtaa siihen määrittelemättömään käyttäytymiseen. Lisäksi POSIX ei täsmennä, missä posix-kuori on sijoitettava, vain sen nimeä ( sh ), joten /bin/sh ei ole taattu oikeaksi poluksi. Eniten kannettavia ei ole millään tavalla määritellä mitään, tai mukauttaa shebang käyttöjärjestelmään.
2 Michael Kjörling 07/30/2017
Laskein neljäsosaa käsikirjani äskettäin, ja en vain voinut selvittää, miksi se ei toiminut; loppujen lopuksi samat komennot toimivat kiinteästi ja tekivät juuri sitä mitä halusin heitä tekemään, kun kokeilin niitä suoraan kuoressa. Heti kun muutin #!/bin/sh #!/bin/bash , komentosarja toimi täydellisesti. (Puolustukseni oli, että käsikirjoitus oli kehittynyt ajan mittaan sellaisesta, joka todella tarvitsi vain sh-ismejä, sellaiseen, joka tukeutui bash-kaltaiseen käyttäytymiseen.)
2 jlliagre 07/30/2017
@ MichaelKjörling (todellinen) Bourne-kuori ei ole miltei Linux-jakeluun liitetty ja se ei kuitenkaan ole POSIX-yhteensopiva. POSIX-standardikuvio luotiin ksh käyttäytymisestä, ei Bourne. Useimmat Linux-jakeluista, jotka seuraavat FHS: ää, on, että /bin/sh on symbolinen linkki heille, jonka he haluavat tarjota POSIX-yhteensopivuuden, yleensä bash tai dash .

Kaz 07/31/2017.

TXR-kieltä valmistelevassa ./configure kirjoitin seuraavaa prologua paremman siirrettävyyden puolesta. Skripti käynnistyy itsestään, vaikka #!/bin/sh ei ole POSIX-yhteensopiva vanha Bourne Shell. (Rakennan jokaisen julkaisun Solaris 10 VM: ssä).

#!/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 

Ajatus tässä on, että löydämme paremman kuoren kuin se, jota aiomme käyttää, ja suorita komentosarja uudelleen käyttäen sitä kuorta. txr_shell ympäristömuuttuja on asetettu niin, että uudelleen toteutettu skripti tietää, että se on uudelleen suoritettu rekursiivinen ilmentymä.

(Käsikirjassani myös txr_shell muuttujaa käytetään myöhemmin tarkalleen kahdelle tarkoitukselle: se tulostetaan osana informatiivista viestiä komentosarjojen lähdössä. Toiseksi se on asennettu SHELL Makefile , joten make käyttää tätä kuorta myös reseptien suorittamiseen.)

Järjestelmässä, jossa /bin/sh on viiva, näet, että yllä oleva logiikka löytää /bin/bash ja suorita komentosarjan uudelleen.

Solaris 10 -laatikossa /usr/xpg4/bin/sh käynnistyy, jos yhtään /usr/xpg4/bin/sh ei löydy.

Prologi on kirjoitettu konservatiiviseen kuori-murteeseen käyttäen test olemassaolevien testien kokeilua ja ${@+"$@"} temppua laajentamalla argumentteja, jotka tarjoavat joitain rikki vanhoja kuoreita (mikä olisi yksinkertaisesti "$@" jos olisimme POSIX-yhteensopivassa kuoressa).

2 comments
Charles Duffy 07/31/2017
Ei tarvitsisi x hakkerointia, jos oikea lainaus oli käytössä, koska tilanteet, jotka määräsivät kyseisen idiomin, ympäröivät nyt vanhentuneita testin kutsumuksia -a tai -o yhdistämällä useita testejä.
Kaz 07/31/2017
@CharlesDuffy Itse asiassa; test x$whatever minä olen tekemässä siellä näyttää sipuli lakalla. Jos emme voi luottaa rikki vanhaan kuoriin lainaamalla, lopullinen ${@+"$@"} yritys on hyödytön.

zwol 07/31/2017.

Kaikki Bourne-kuorikielen muutokset ovat objektiivisesti kauheita verrattuna moderneihin komentojonoihin kuten Perl, Python, Ruby, node.js ja jopa (todennäköisesti) Tcl. Jos sinun on tehtävä jotain jopa vähän monimutkaista, sinun tulee olemaan onnellisempi pitkällä aikavälillä, jos käytät jotain yllä mainituista komentotiedostoista.

Yksi ja ainoa etu, että kuoren kieli on vielä uusilla kielillä, on se, että something itse kutsuu itselleen /bin/sh on taattu olemassa olevalle jotain, joka pitää Unixia. Tämä ei kuitenkaan ehkä ole POSIX-yhteensopiva; monet vanhasta Unixes-käyttöjärjestelmästä jäädytti /bin/sh ja apuohjelmien toteuttamat kielet oletuksena PATH: ssa prior Unix95: n vaatimia muutoksia (kyllä, Unix95, kaksikymmentä vuotta sitten ja laskemalla). Saattaa olla joukko Unix95 tai jopa POSIX.1-2001, jos olet onnekas, työkaluja hakemistossa, joka not oletusarvoinen PATH (esim. /usr/xpg4/bin ), mutta niitä ei taata olemassa.

Perlin perusteet ovat more likely läsnä mielivaltaisesti valitulla Unix-asennuksella kuin Bash is. ("Perlin perusasiat" tarkoitan /usr/bin/perl olemassa ja on some , ehkä aika vanhana, Perl 5: n versiota ja jos olette onnekas, tulkkiversion mukana toimitetut moduulit käytettävissä.)

Siksi:

Jos kirjoitat jotain, joka on tehtävä everywhere , joka olet Unix (kuten "configure" -komento), sinun on käytettävä #! /bin/sh #! /bin/sh , eikä sinun tarvitse käyttää mitä tahansa laajennusta. Nykyään kirjoittaisin POSIX.1-2001-yhteensopivaa kuorta tässä tilanteessa, mutta olisin valmis korjaamaan POSIXisms, jos joku pyysi tukea ruostuneelle raudalle.

Mutta jos et kirjoita jotain, joka on työskenneltävä kaikkialla, niin hetki, jona olet kiusattu käyttämään kaikkia Bashismia lainkaan, sinun pitäisi lopettaa ja kirjoittaa koko asia paremmalla komentosarjalla. Tulevaisuutesi kiittää sinua.

(Joten, milloin is tarkoituksenmukaista käyttää Bash-laajennuksia?) Ensimmäisen tilauksen: ei koskaan Toista tilausta: vain laajentaa Bash-vuorovaikutusympäristöä - esimerkiksi antaa älykkään välilehden valmistumisen ja fancy-ohjeet.)

Related questions

Hot questions

Language

Popular Tags