#! / bin / sh vs #! / bin / bash para sa maximum na maaaring dalhin

cherouvim 09/03/2017. 3 answers, 2.821 views
linux bash shell sh

Karaniwang gumagana ako sa mga server ng Ubuntu LTS na mula sa kung ano ang naiintindihan ko symlink /bin/sh sa /bin/dash . Maraming iba pang mga distros bagaman symlink /bin/sh sa /bin/bash .

Mula sa nauunawaan ko na kung ang isang script ay gumagamit ng #!/bin/sh sa itaas hindi ito maaaring tumakbo sa parehong paraan sa lahat ng mga server?

Mayroon bang isang iminungkahing pagsasanay na kung saan ang shell na gagamitin para sa mga script kapag ang isa ay nais ng maximum na maaaring dalhin ng mga script sa pagitan ng mga server?

1 Comments
Thorbjørn Ravn Andersen 08/01/2017
Mayroong bahagyang pagkakaiba sa pagitan ng iba't ibang mga shell. Kung maaaring dalhin ang pinakamahalaga sa iyo pagkatapos ay gamitin ang #!/bin/sh at huwag gumamit ng anumang bagay kaysa sa kung ano ang ibinigay ng orihinal na shell.

3 Answers


Gordon Davisson 08/01/2017.

Mayroong halos apat na mga antas ng maaaring dalhin para sa mga script ng shell (kasing layo ng linya ng shebang ay nababahala):

  1. Karamihan sa mga portable: gumamit ng isang #!/bin/sh shebang at gamitin only ang pangunahing syntax ng shell na tinukoy sa pamantayan ng POSIX . Ito ay dapat magtrabaho sa medyo marami anumang POSIX / unix / linux system. (Bueno, maliban sa Solaris 10 at mas maaga kung saan ay may real legacy Bourne shell, na predating POSIX kaya hindi sumusunod, bilang /bin/sh .)

  2. Ikalawang pinaka-portable: gumamit ng isang #!/bin/bash (o #!/usr/bin/env bash ) na linya ng shebang, at patungo sa mga tampok na bash v3. Ito ay gagana sa anumang sistema na may bash (sa inaasahang lokasyon).

  3. Ikatlo ang pinaka portable: gumamit ng #!/bin/bash (o #!/usr/bin/env bash ) na shebang line, at gamitin ang mga tampok na bash v4. Mabibigo ito sa anumang sistema na may bash v3 (eg macOS, na dapat itong gamitin para sa mga dahilan sa paglilisensya).

  4. Hindi bababa sa portable: gumamit ng #!/bin/sh shebang at gamitin ang mga extension ng bash sa POSIX shell syntax. Ito ay mabibigo sa anumang sistema na may iba pang kaysa sa bash para sa / bin / sh (tulad ng kamakailang mga bersyon ng Ubuntu). Huwag kailanman gawin ito; ito ay hindi lamang isang isyu sa compatibility, ito ay lamang plain mali. Sa kasamaang palad, ito ay isang pagkakamali ng maraming tao.

Ang aking rekomendasyon: gamitin ang pinaka-konserbatibo ng unang tatlong na nagbibigay ng lahat ng mga tampok ng shell na kailangan mo para sa script. Para sa max portability, gamitin ang opsyon # 1, ngunit sa aking karanasan ang ilang mga tampok ng bash (tulad ng mga array) ay kapaki-pakinabang na kakailanganin kong pumunta sa # 2.

Ang pinakamasama bagay na maaari mong gawin ay # 4, gamit ang maling shebang. Kung hindi ka sigurado kung anong mga tampok ang pangunahing POSIX at kung saan ay mga extension ng bash, alinman sa stick sa isang bash shebang (ie opsyon # 2), o subukan ang script na lubusan sa isang napaka basic shell (tulad ng gitling sa iyong mga server ng Ubuntu LTS). Ang Ubuntu wiki ay may isang mahusay na listahan ng mga bashisms upang panoorin para sa .

Mayroong ilang mga napakahusay na impormasyon tungkol sa kasaysayan at mga pagkakaiba sa pagitan ng mga shell sa Unix at Linux na tanong "Ano ang ibig sabihin ng pagiging magkatugma?" at ang tanong Stackoverflow "Pagkakaiba sa pagitan ng sh at Bash" .

Gayundin, magkaroon ng kamalayan na ang shell ay hindi lamang ang bagay na naiiba sa pagitan ng iba't ibang mga sistema; kung ginagamit mo sa linux, ginagamit mo ang mga utos ng GNU, na may maraming mga hindi karaniwang mga extension na hindi mo maaaring makita sa ibang mga sistema ng unix (hal. bsd, macOS). Sa kasamaang palad, walang simpleng panuntunan dito, kailangan mo lamang malaman ang hanay ng pagkakaiba-iba para sa mga utos na iyong ginagamit.

Isa sa mga nastiest utos sa mga tuntunin ng maaaring dalhin ay isa sa mga pinaka basic: echo . Anumang oras na gamitin mo ito sa anumang mga pagpipilian (hal. echo -n o echo -e ), o sa anumang escapes (backslashes) sa string upang i-print, iba't ibang mga bersyon ay magkakaroon ng iba't ibang mga bagay. Anumang oras na nais mong i-print ang isang string na walang isang linefeed pagkatapos nito, o sa escapes sa string, gamitin ang printf halip (at malaman kung paano ito gumagana - ito ay mas kumplikado kaysa sa echo ay). Ang ps command ay isa ring gulo .

Isa pang pangkalahatang bagay-to-watch-for ay kamakailang / GNUish extension sa command option syntax: ang lumang (karaniwang) command na format ay ang utos ay sinusundan ng mga opsyon (na may isang dash, at ang bawat pagpipilian ay isang solong titik) command arguments. Ang mga kamakailang (at madalas na di-portable) na mga variant ay may mga mahahabang opsyon (kadalasang ipinakilala sa -- ), na nagpapahintulot sa mga pagpipilian na makalipas pagkatapos ng mga argumento, at paggamit -- upang paghiwalayin ang mga opsyon mula sa mga argumento.

5 comments
12 pabouk 07/30/2017
Ang ikaapat na opsiyon ay isang maling ideya lamang. Mangyaring huwag gamitin ito.
3 Gordon Davisson 07/30/2017
@pabouk Sumasang-ayon ako nang lubusan, kaya inedit ko ang sagot ko upang gawin itong mas malinaw.
1 jlliagre 07/30/2017
Ang iyong unang pahayag ay bahagyang nakaliligaw. Ang pamantayan ng POSIX ay hindi tumutukoy sa anumang bagay tungkol sa shebang sa labas ng pagsasabi sa paggamit nito ay humahantong sa hindi tinukoy na pag-uugali. Bukod dito, ang POSIX ay hindi tumutukoy kung saan dapat matatagpuan ang posix shell, lamang ang pangalan nito ( sh ), kaya /bin/sh ay hindi garantisadong maging tamang landas. Ang pinaka-portable ay pagkatapos ay hindi upang tukuyin ang anumang shebang sa lahat, o upang iakma ang shebang sa OS na ginagamit.
2 Michael Kjörling 07/30/2017
Nahulog ako sa # 4 sa isang script ng mina kamakailan lamang, at hindi ko maunawaan kung bakit hindi ito gumagana; Pagkatapos ng lahat, ang parehong mga utos ay gumagawang matatag, at ginawa ang eksaktong nais kong gawin nila, nang direkta ko silang sinubukan sa shell. Sa sandaling binago ko ang #!/bin/sh sa #!/bin/bash bagaman, ang script ay nagtrabaho nang perpekto. (Sa aking depensa, ang script na lumaki sa paglipas ng panahon mula sa isa na talagang kailangan lang sh-isms, sa isa na umaasa sa bash-tulad ng pag-uugali.)
2 jlliagre 07/30/2017
@ MichaelKjörling Ang (totoo) Bourne shell ay halos hindi kailanman na kasama ng mga distribusyon ng Linux at hindi pa rin POSIX compliant. Ang POSIX standard shell ay nilikha mula sa ksh uugali, hindi Bourne. Ano ang karamihan sa mga distribusyon ng Linux na sumusunod sa FHS ay ang pagkakaroon ng /bin/sh na isang sinasagisag na link sa shell na pinili nila upang magbigay ng POSIX compatibility, karaniwang bash o dash .

Kaz 07/31/2017.

Sa. ./configure script na naghahanda ng wika ng TXR para sa pagtatayo, isinulat ko ang sumusunod na prologo para sa mas mahusay na maaaring dalhin. Ang script ay bootstrap mismo kahit na ang #!/bin/sh ay isang non-POSIX-conforming old Bourne Shell. (Bumuo ako ng bawat release sa isang Solaris 10 VM).

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

Ang ideya dito ay nakahanap kami ng isang mas mahusay na shell kaysa sa kung saan kami ay tumatakbo sa ilalim, at muling isagawa ang script gamit ang shell na iyon. Ang variable na environment ng txr_shell ay nakatakda, upang malaman ng re-executed na script na ito ay ang re-executed recursive na halimbawa.

(Sa aking script, ang txr_shell variable ay ginagamit din pagkatapos, para sa eksaktong dalawang layunin: una ito ay nakalimbag bilang bahagi ng isang impormasyon na mensahe sa output ng script. Ikalawa, ito ay naka-install bilang SHELL variable sa Makefile , upang make ay gagamitin din ang shell na ito para sa pagpapatupad ng mga recipe.)

Sa isang sistema kung saan /bin/sh ay gitling, makikita mo na makikita sa itaas ang logic /bin/bash at muling isasagawa ang script na iyon.

Sa isang kahon ng Solaris 10, ang /usr/xpg4/bin/sh ay magpapatuloy kung hindi makikita ang Bash.

Ang prologo ay nakasulat sa isang konserbatibong shell dialect, gamit ang test para sa mga test sa pagkakaroon ng file, at ang ${@+"$@"} trick para sa pagpapalawak ng mga argumento na nakatakda sa ilang mga nasira na lumang shell (na kung saan ay magiging "$@" kung tayo ay sa isang POSIX conforming shell).

2 comments
Charles Duffy 07/31/2017
Ang isa ay hindi na kailangan ang x hackery kung ang tamang pagbanggit ay ginagamit, dahil ang mga sitwasyon na nag-utos na idiom ay palibutan ngayon-hindi na ginagamit ang mga pagsubok sa mga invocation na may -a o -o pagsamahin ang maraming mga pagsubok.
Kaz 07/31/2017
@CharlesDuffy Sa katunayan; ang test x$whatever ginagawa ko doon mukhang isang sibuyas sa barnisan. Kung hindi namin mapagkakatiwalaan ang sirang lumang shell upang gawin ang pag-quote, pagkatapos ay ang walang katapusan na ${@+"$@"} pagtatangka ay walang kabuluhan.

zwol 07/31/2017.

Ang lahat ng mga pagkakaiba-iba ng wika ng Bourne shell ay talagang napakahirap sa paghahambing sa mga modernong mga scripting language tulad ng Perl, Python, Ruby, node.js, at kahit (arguably) Tcl. Kung kailangan mong gumawa ng anumang bagay kahit na medyo kumplikado, ikaw ay magiging mas masaya sa katagalan kung gumagamit ka ng isa sa itaas sa halip ng isang script ng shell.

Ang isa at tanging bentahe ng shell language pa rin ay may higit sa mga mas bagong wika ay na ang something tinatawag na mismo /bin/sh ay garantisadong na umiiral sa anumang bagay na purports na Unix. Gayunpaman, ang isang bagay ay hindi maaaring maging sumusunod sa POSIX; marami sa mga may-ari ng Unixes na may pamana ang nagpapaligid sa wikang ipinatupad ng /bin/sh at ang mga utility sa default na PATH prior ang mga pagbabago na hinihingi ng Unix95 (oo, Unix95, dalawampung taon na ang nakakaraan at nagbibilang). Maaaring mayroong isang set ng Unix95, o kahit POSIX.1-2001 kung ikaw ay masuwerteng, mga tool sa isang direktoryo na not sa default na PATH (eg /usr/xpg4/bin ) ngunit hindi sila garantisadong umiiral.

Gayunpaman, ang mga pangunahing kaalaman ng Perl ay more likely na naroroon sa isang naka-arbitrary na piniling pag-install ng Unix kaysa sa Bash. (Sa pamamagitan ng "mga pangunahing kaalaman ng Perl" ibig sabihin ko /usr/bin/perl umiiral at ang some , posibleng lubos na luma, bersyon ng Perl 5, at kung ikaw ay masuwerteng ang hanay ng mga module na ipinadala sa bersyon na iyon ng interpreter ay magagamit.)

Samakatuwid:

Kung nagsusulat ka ng isang bagay na dapat magtrabaho sa everywhere na nagmamay-ari na Unix (tulad ng isang "configure" na script), kailangan mong gamitin ang #! /bin/sh #! /bin/sh , at kailangan mong huwag gumamit ng anumang mga extension kahit ano pa man. Ngayong mga araw na ito ay isusulat ko ang POSIX.1-2001-compliant shell sa pangyayari na ito, ngunit magiging handa akong mag-patch out POSIXisms kung may humingi ng suporta para sa kalawang na bakal.

Ngunit kung not nagsusulat ng isang bagay na dapat magtrabaho sa lahat ng dako, pagkatapos sa sandaling matukso kang gumamit ng anumang Bashism sa lahat, dapat mong ihinto at isulat ang buong bagay sa isang mas mahusay na wika sa pag-script. Ang iyong sarili sa hinaharap ay salamat sa iyo.

(Kaya kapag angkop na gamitin ang mga extension ng Bash? Para sa unang order: hindi kailanman. Upang pangalawang order: para lamang mapalawak ang Bash interactive na kapaligiran - halimbawa upang magbigay ng smart tab-pagkumpleto at magarbong mga senyas.)

Related questions

Hot questions

Language

Popular Tags