Ці з'яўляецца тэст або [або [[больш партатыўнымі і паміж Баш абалонак і паміж іншымі абалонкамі?

Я бачу, што я магу зрабіць

$ [ -w /home/durrantm ] && echo "writable"
writable

або

$ test -w /home/durrantm && echo "writable"
writable

або

$ [[ -w /home/durrantm ]] && echo "writable"
writable

I like using the third syntax. Are they equivalent in all ways and fабо all negative and edge cases? Are there any differences in pабоtability, e.g. between bash on Ubuntu and on OS X або older/newer bash versions, e.g. befабоe/after 4.0 and do they both expand expressions the same way?

42
Для [...] супраць [[...]] супраць тэст ... , ёсць больш поўныя адказы ў this асноўным дублікат пытанне .
дададзена аўтар Valters Vingolds, крыніца
Для канкрэтнага пытання тэставання на writability файла, глядзіце таксама Як неинвазивный тэст для доступу на запіс у файл <?/а>
дададзена аўтар G-Man, крыніца
Існуе прымаўка: «няма пераноснага кода, які быў партаваны толькі код». Мая парада ў дачыненні да гэтага: Выкарыстоўвайце найбольш чытаны выгляд (верагодна, [[...]]) і паспрабаваць яго на ўсіх платформах, якія вы хочаце падтрымліваць. Існуе не так шмат карысці ў затеняя вашы сцэнары, каб яны працуюць на старажытных платформах, што ні вы, ні ваша мэтавая аўдыторыя выкарыстоўвае. Гэта будзе проста зрабіць код цяжка чытаць, ўводзіць непатрэбныя памылкі і, магчыма, нават праблемы бяспекі (як гэта зрабіў для OpenSSL).
дададзена аўтар Sam Gamoran, крыніца

7 адказы

Так, ёсць адрозненні. Найбольш партатыўны з'яўляюцца тэст або [] . Яны з'яўляюцца часткай POSIX тэст спецыфікацыі </а>.

<�Код>, калі ... ц канструкт таксама

вызначаецца POSIX і павінна быць цалкам партатыўным.

<�Код> [[]] гэта КШ функцыя, якая таксама прысутнічае ў некаторых версіях баш ( ўсе сучасныя ) у ЗШ і, магчыма, у іншых, але няма ў ш або працяжнік або розныя іншыя простыя снарады.

Такім чынам, каб зрабіць вашыя скрыпты партатыўнымі, выкарыстоўвайце [] , тэст з , калі ... ц .

34
дададзена
Адна цікавая асаблівасць [[ з'яўляецца тое, што раскладання параметраў не павінны быць указаны: [[- е $ файла]] падзея працуе, калі $ файл змяшчае пробельные сімвалы.
дададзена аўтар Matt Enright, крыніца
@helpermethod таксама, убудаваныя рэгулярныя выразы [[$ а = ~ ^ р. * экспа. * $ »]]
дададзена аўтар GnP, крыніца
Проста да ведама, баш і ЗШ ужо падтрымліваецца [[ на працягу вельмі доўгага часу ( Баш дадаў яго ў канца 90-х, ЗШ не пазней 2000 года, і я быў бы здзіўлены, калі гэта <�я> альбо </я> бракавала падтрымкі), так што вы наўрад ці сустрэнеце версію альбо без [[. Сустрэўшы іншую POSIX-сумяшчальнай абалонкі (напрыклад, працяжнік ) з'яўляецца значна больш верагодным.
дададзена аўтар Luke Smith, крыніца

[ is synonym of the test command and it is simultaneously a bash builtin and separate command. But [[ is a bash keyword and works in some versions only. So for reasons of portability you are better off using single [] or test

[ -w "/home/durrantm" ] && echo "writable"
28
дададзена

Please note, that [] && cmd Хіба не тое ж самаеif .. fi construction.

Sometimes its behaviour its pretty similar and you can use [] && cmd instead of if .. fi. But only sometimes. If you have more then one command to execute if condition or you need if .. else .. fi be careful and whatch the logic.

Некалькі прыкладаў:

[ -z "$VAR" ] && ls file || echo wiiii

Хіба не тое ж самае

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

таму што калі Ls не атрымаецца, рэха будзе выконвацца, які не адбудзецца з , калі .

Іншы прыклад:

[ -z "$VAR" ] && ls file && echo wiii

Хіба не тое ж самае

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

хоць гэтая канструкцыя будзе дзейнічаць гэтак жа

[ -z "$VAR" ] && { ls file ; echo wiii ; }

Звярніце ўвагу, пасля таго, як рэха важна і павінна быць там.

Такім чынам, узнаўляючы заяву вышэй, мы можам сказаць,

[] && cmd == if first command is successful then execute the next one

if .. fi == if condition (which may be the test command as well) then execute command(s)

Такім чынам, для пераноснасці паміж [ і [[ выкарыстанне [ толькі.

if is POSIX compatible. So if you have to choose between [ and if choose looking at your task and expected behaviour.

19
дададзена
Я downvoted, таму што а) гэта ў асноўным добры адказ, але адказ на іншае пытанне. б) вы ўяўляеце [ і , калі , як subtitutes, але яны не з'яўляюцца. Гэта на самай справе && які замяніўшы , калі . <�Код> [ выконвае код і вяртае статус, гэтак жа, як Ls і Grep будзе. <�Код>, калі галіны выканання ў залежнасці ад стану вяртання каманды (заява) дадзена пасля таго, як, калі гэта можа быць любая каманда (аператар). <�Код> && выконвае наступны аператар, толькі калі папярэдняя адзін які вяртаецца 0, гэтак жа, як просты if..then..fi .
дададзена аўтар GnP, крыніца
@rush вы маеце рацыю, я прапусціў гісторыю рэдагавання там. Мае выбачэнні. Як я ўжо сказаў, гэта ў асноўным добры адказ, таму я выпростваецца мой голас.
дададзена аўтар GnP, крыніца
Я, напэўна, проста быць шчыльным, але я не бачу, што розніца была б ... не маглі б вы прывесці прыклад, калі гэтыя дзве канструкцыі будуць даваць розныя вынікі?
дададзена аўтар evilsoup, крыніца
@evilsoup, абнаўляецца. Можа быць, я не самы лепшы объяснителем, хоць я спадзяюся, што гэта будзе ясна.
дададзена аўтар agrublev, крыніца
@gnp, добра. а) праверце каментар ад Майкла. Існуе кароткае тлумачэнне, што першапачаткова быў іншае пытанне. Я проста пакінуў адказ на гісторыю. б) адказ быў у асноўным пра розніцу паміж && .. || і калі .. яшчэ .. фі .
дададзена аўтар agrublev, крыніца
Зроблена пытанне будзе пра [супраць [[супраць тэсту і таксама не пра тое, калі ... фі супраць &&, каб зрабіць гэта будзе адно пытанне. На жаль, зрабіць гэта робіць гэты адказ, здаецца, па-за кропкі. Прашу прабачэння за не атрымліваюць пытанне м руды першапачаткова была арыентавана, што прывяло да гэтага. Жыві і (спрабуюць) вучыцца. :)
дададзена аўтар ExpelledFromParadise, крыніца
Вельмі добрыя моманты, чарот. Я мяркую, бяспечная форма вашага 1-га прыкладу будзе: [-z «$ VAR»] && {файл Ls; праўда; } || рэха wiiii . Гэта крыху больш шматслоўным, але гэта па-ранейшаму менш, чым , калі ... ц будаўніцтва.
дададзена аўтар DirkGently, крыніца

It's actually the && that is replacing the if, not the test: an if statement in shell scripting tests whether a command returned a "successful" (zero) exit status; in your example, the command is [.

Такім чынам, ёсць на самай справе дзве рэчы, якія розныя тут: каманда выкарыстоўваецца для выканання тэсту, і сінтаксіс, які выкарыстоўваецца для выканання кода на аснове выніку гэтага тэсту.

Тэставыя каманды:

  • test is a standardised command for evaluating properties of strings and files; in your example, you are running the command test -w /home/durrantm
  • [ is an alias of that command, equally standardised, which has a mandatory last argument of ] in order to look like a bracketed expression; don't be fooled, it's still just a command (you may even find that your system has a file called /bin/[)
  • [[ is an extended version of the test command built into some shells, but not part of the same POSIX standard; it includes extra options which you are not using here

Ўмоўныя выразы:

  • The && operator (standardised here) performs a logical AND operation, by evaluating two commands and returning 0 (which represents true) if they both return 0; it will only evaluate the second command if the first one returned zero, so it can be used as a simple conditional
  • The if ... then ... fi construct (standardised here) uses the same method of judging "truth", but allows for a compound list of statements in the then clause, rather than the single command afforded by an && short-circuit, and provides elif and else clauses, which are hard to write using only && and ||. Note that there are no brackets around the condition in an if statement.

Такім чынам, наступныя ўсе аднолькава партатыўныя і цалкам эквівалентныя, перакладанне вашага прыкладу:

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

Хоць ніжэйзгаданае таксама эквівалентныя, але менш пераносным з-за нестандартнага характару [[:

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi
9
дададзена
Ды я здабываў калі .... фі частка, каб зрабіць гэта будзе адно пытанне.
дададзена аўтар ExpelledFromParadise, крыніца

Калі вы хочаце партатыўнасць па-за Bourne-падобны свет, то:

test -w /home/durrantm && echo writable

з'яўляецца самым партатыўным. Ён працуе ў абалонках Bourne, CSH і гс сям'і.

test -w /home/durrantm && echo "writable"

будзе выводзіць "запіс" замест запісы у абалонках гс сямейства ( гс , эс , akanga , дзе " не з'яўляецца спецыяльным).

[ -w /home/durrantm ] && echo writable

не будзе працаваць у абалонках CSH або гс сям'і на сістэмах, якія не маюць [ Каманда ў $ PATH (некаторыя з іх былі вядомыя, каб мець тэст , але не яго [ псеўданім).

if [ -w /home/durrantm ]; then echo writabe; fi

працуе толькі ў абалонках сямейства Bourne.

[[ -w /home/durrantm ]] && echo writable

працуе толькі ў КШ (дзе яна ўзнікла), ЗШ і баш (усе 3 у сям'і Bourne).

Ніхто не будзе працаваць у рыбы абалонкі, дзе вам трэба:

[ -w /home/durrantm ]; and echo writable

альбо:

if [ -w /home/durrantm ]; echo writable; end
7
дададзена

Для пераноснасці, выкарыстоўвайце тэст / [. Але калі вам не патрэбна партатыўнасць, дзеля здаровае сябе і іншых, чытаючы ваша выкарыстанне сцэнарыя [[. :)

Таксама гл У чым розніца паміж тэстам, [і [[? у BashFAQ .

7
дададзена

My most important reason for choosing either if foo; then bar; fi or foo && bar is whether the exit status of the whole command is important.

Для параўнання:

#!/bin/sh
set -e
foo && bar
do_baz

з:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

Можна падумаць, што яны робяць тое ж самае; Аднак, калі Foo не ўдаецца (або ілжывая, у залежнасці ад вашага пункту гледжання), то ў першым прыкладзе do_baz не будзе выкананы, бо сцэнар будзе выйшаў ... У усталяваны -e інструктуе абалонку, каб выйсці неадкладна, калі любая каманда вяртае ілжывае стан. Вельмі карысна, калі вы робіце такія рэчы, як:

cd /some/directory
rm -rf *

Вы не хочаце, каб скрыпт працягваць працаваць, калі CD не можа па якой-небудзь прычыне.

0
дададзена
Няма правалу спробы Foo не перапыніць сцэнар у любым выпадку. Гэта асаблівы выпадак для набор -e (калі каманда ацэньваецца як ўмова (злева ад некаторага &&/|| або, калі/падчас/да/ELSIF ... умоў). А адсутнасць бар будзе выходзіць з корпуса ў абедзвюх выпадках.
дададзена аўтар Stéphane Chazelas, крыніца
Вы хочаце Кд/некаторыя/Каталог && ет -rf - * або Кд/некаторыя/каталог || выхад; ГТ -rf - * (да гэтага часу не выдаляе схаваныя файлы). Я асабіста не падабаецца ідэя выкарыстання набор -e у якасці падставы, каб не зрабіць намаганне, каб напісаць правільны код.
дададзена аўтар Stéphane Chazelas, крыніца