Jaký je rozdíl mezi operátory Bash [[vs [vs (vs ((?

) Jsem trochu zmatený, co dělají tito operátoři jinak, když používá se v bash (závorky, dvojité závorky, závorky a dvojité závorky).

[[ , [ , ( , (( 

Viděl jsem, jak je lidé používají, pokud jsou takové výroky:

if [[condition]] if [condition] if ((condition)) if (condition) 

Komentáře

Odpovědět

V prostředí Bourneových skořápek příkaz if obvykle vypadá jako

if command-list1 then command-list2 else command-list3 fi 

Klauzule then je provedena, pokud je ukončovací kód seznam příkazů je nulový. Pokud je kód ukončení nenulový, je provedena klauzule else. command-list1 může být jednoduché nebo složité. Může to být například posloupnost jednoho nebo více kanálů oddělených jedním z operátorů ;, &, &&, || nebo nový řádek. Níže uvedené if podmínky jsou jen speciální případy command-list1:

  1. if [ condition ]

    [ je jiný název pro tradiční příkaz test. [ / test je standardní obslužný program POSIX. Všechny skořápky POSIX to mají vestavěné (i když to POSIX² nevyžaduje). Příkaz test nastaví výstupní kód a příkaz if jedná podle toho. Typické testy jsou, zda soubor existuje, nebo se jedno číslo rovná druhému.

  2. if [[ condition ]]

    Toto je nová upgradovaná variace na test ¹ z ksh that bash , zsh , yash , busybox sh také podporují. Tato konstrukce [[ ... ]] také nastavuje kód ukončení a if jedná odpovídajícím způsobem. Mezi rozšířenými funkcemi může otestovat, zda řetězec odpovídá zástupnému vzoru (ne v busybox sh ).

  3. if ((condition))

    Další rozšíření ksh , které bash a zsh také podporují. Toto provádí aritmetiku. V důsledku aritmetiky je nastaven výstupní kód a příkaz if funguje podle rdingly. Vrátí výstupní kód s nulou (true), pokud je výsledek aritmetického výpočtu nenulový. Stejně jako [[...]] není tento formulář POSIX, a proto není přenosný.

  4. if (command)

    Spustí příkaz v subshellu. Když je příkaz dokončen, nastaví výstupní kód a příkaz if se bude chovat odpovídajícím způsobem.

    Typickým důvodem pro použití takového subshellu je omezení vedlejších účinků command pokud command vyžaduje přiřazení proměnných nebo jiné změny prostředí prostředí. Tyto změny po dokončení subshellu nezůstanou.

  5. if command

    je spuštěn příkaz a příkaz if je aktivní podle jeho výstupního kódu.


¹ i když ne ve skutečnosti příkaz, ale speciální konstrukce shellu s vlastní samostatnou syntaxí od syntaxe normálního příkazu, a výrazně se liší mezi implementacemi prostředí

² POSIX vyžaduje, aby existovaly samostatné test a [ nástroje v systému, i když v případě [ je známo několik linuxových distribucí jako m to je.

Komentáře

  • Děkujeme, že jste zahrnuli 5. možnost. Tento ‚ klíč k pochopení toho, jak to ve skutečnosti funguje a je překvapivě nedostatečně využíváno.
  • Všimněte si, že [ je ve skutečnosti binární, nikoli interní příkaz nebo symbol. Obecně žije v /bin.
  • @JulienR. Vlastně [ je vestavěný, stejně jako test. Z důvodu kompatibility jsou k dispozici binární verze. Podívejte se na help [ a help test.
  • za zmínku stojí, že zatímco ((isnt POSIX, tj. aritmetická expanze je a ‚ je snadno zaměnitelná. Řešením je často použít něco jako [ $((2+2)) -eq 4 ] využít aritmetiku v podmíněných výrokech.
  • Přál bych si, abych mohl tuto odpověď hlasovat vícekrát. Perfektní vysvětlení.

Odpověď

  • (…) závorky označují subshell . To, co v nich není, není výraz jako v mnoha jiných jazycích. Je to seznam příkazů (stejně jako mimo závorky). Tyto příkazy jsou prováděny v samostatném podprocesu, takže jakékoli přesměrování, přiřazení atd. Provedené v závorkách nemá žádný účinek mimo závorky.
    • S úvodním znak dolaru, $(…) je nahrazení příkazu : uvnitř závorek je příkaz a výstup z příkazu se používá jako součást příkazového řádku (po zvláštních rozšířeních, pokud není substituce mezi uvozovkami, ale to je jiný příběh ).
  • { … } závorky jsou jako závorky v tom, že seskupují příkazy, ale ovlivňují pouze analýzu, nikoli seskupení. Program x=2; { x=4; }; echo $x vytiskne 4, zatímco x=2; (x=4); echo $x vytiskne 2. (Rovněž je třeba oddělit závorky jako klíčová slova a nalezen v pozici příkazu (odtud tedy mezera za { a ; před }) vzhledem k tomu závorky nejsou „t. To je jen syntaxe.“
    • S předním znakem dolaru je ${VAR} rozšíření parametrů , rozšiřující se na hodnotu proměnné, s možnými transformacemi navíc. Prostředí ksh93 podporuje také ${ cmd;} jako formu nahrazování příkazů, která nevytváří subshell.
  • ((…)) dvojité závorky obklopují aritmetickou instrukci , tj. výpočet na celá čísla, s syntaxe podobná jiným programovacím jazykům. Tato syntaxe se většinou používá pro přiřazení a v podmíněných podmínkách. Existuje pouze v ksh / bash / zsh, ne v obyčejném sh.
    • Stejná syntaxe se používá v aritmetických výrazech $((…)), které se rozšíří na celočíselnou hodnotu výrazu.
  • [ … ] prostorové závorky podmíněné výrazy . Podmíněné výrazy jsou většinou postaveny na operátorech , jako je -n "$variable" k otestování, zda je proměnná prázdná, a -e "$file" k otestování, zda soubor existuje. Všimněte si, že kolem každého potřebujete mezeru operátor (např. [ "$x" = "$y" ], ne [ "$x"="$y" ] ) a mezeru nebo znak jako ; uvnitř i vně závorek (např. [ -n "$foo" ], ne [-n "$foo"] ).
  • [[ … ]] dvojité závorky jsou alternativní formou podmíněných výrazů v ksh / bash / zsh s několika dalšími funkcemi, například můžete napsat [[ -L $file && -f $file ]] k otestování, zda je soubor symbolickým odkazem na běžný soubor, zatímco jednotlivé závorky vyžadují [ -L "$file" ] && [ -f "$file" ]. Další informace o tomto tématu najdete v části Proč rozšíření parametrů o mezery bez uvozovek funguje v dvojitých závorkách [[ale ne v jednoduchých závorkách [? ].

V shellu je every příkaz podmíněným příkazem: každý příkaz má návratový stav, který je buď 0 označující úspěch, nebo celé číslo mezi 1 a 255 (a případně více v některých skořápkách) označující selhání. Příkaz [ … ] (nebo [[ … ]] syntaxe formuláře) je konkrétní příkaz, který lze také hláskovat test … a uspěje, když soubor existuje, nebo když řetězec není prázdný, nebo když je číslo menší než jiné atd. ((…)) syntaxe je úspěšná, když je číslo nenulové .Zde je několik příkladů podmíněnosti ve skriptu prostředí:

  • Vyzkoušejte, zda myfile obsahuje řetězec hello:

    if grep -q hello myfile; then … 
  • Pokud je mydir adresář, přejděte na udělejte to:

    if cd mydir; then echo "Creating mydir/myfile" echo "some content" >myfile else echo >&2 "Fatal error. This script requires mydir to exist." fi 
  • Vyzkoušejte, zda existuje soubor s názvem myfile v aktuálním adresáři:

    if [ -e myfile ]; then … 
  • Totéž, ale také včetně visících symbolických odkazů:

    if [ -e myfile ] || [ -L myfile ]; then … 
  • Vyzkoušejte, zda je hodnota x (o které se předpokládá, že je číselná) alespoň 2, přenositelně:

    if [ "$x" -ge 2 ]; then … 
  • Vyzkoušejte, zda je hodnota x (o které se předpokládá, že je číselná) je alespoň 2, v bash / ksh / zsh:

    if ((x >= 2)); then … 

Komentáře

  • Upozorňujeme, že jedna závorka podporuje -a místo &&, takže lze psát: [ -L $file -a -f $file ], což je stejný počet znaků v závorkách bez dalších [ a ]
  • @AlexisWilke Provozovatelé -a a -o jsou problematické, protože mohou vést k nesprávným analýzám, pokud některé zúčastněné operandy vypadají jako operátoři. Proto je ‚ proto nezmíním ‚: mají nulovou výhodu a don ‚ vždy nefunguje. A nikdy nezapisujte neuvedené proměnné expanze bez dobrého důvodu: [[ -L $file -a -f $file ]] je v pořádku, ale s jednoduchými závorkami potřebujete [ -L "$file" -a -f "$file" ] (což je v pořádku, např. Pokud $file vždy začíná / nebo ./).
  • it ‚ s [[ -L $file && -f $file ]] (no -a s [[...]] varianta).

Odpověď

[ vs [[

Tato odpověď se bude týkat [ vs [[ podmnožina otázky.

Některé rozdíly v Bash 4.3.11:

  • Rozšíření POSIX vs Bash:

  • normální příkaz vs. magie

    • [ je jen běžný příkaz s podivným názvem.

      ] je pouze poslední argument [.

    Ubuntu 16.04 pro něj ve skutečnosti má spustitelný soubor na /usr/bin/[ poskytnutý coreutils , ale integrovaná verze bash má přednost.

    Nic se nezmění způsobem, kterým Bash analyzuje příkaz.

    Zejména < je přesměrování, && a || zřetězí více příkazů, ( ) vygeneruje dílčí skořápky, pokud neunikne \ a rozšíření slov proběhne jako obvykle.

    • [[ X ]] je jediný konstrukt, který umožňuje magickou analýzu X. <, &&, || a () jsou zpracovávána speciálně a pravidla pro dělení slov jsou různá.

      Existují také další rozdíly, jako = a =~ .

    V Bashese: [ je integrovaný příkaz a [[ je klíčové slovo: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && a ||

    • [[ a = a && b = b ]]: pravda, logické and
    • [ a = a && b = b ]: syntaktická chyba, && analyzován jako oddělovač příkazů AND cmd1 && cmd2
    • [ a = a ] && [ b = b ]: POSIX spolehlivý ekvivalent
    • [ a = a -a b = b ]: téměř ekvivalent, ale zastaralý POSIXem, protože je šílený a selže pro některé hodnoty a nebo b jako ! nebo ( které by byly interpretovány jako logické operace
  • (

    • [[ (a = a || a = b) && a = b ]]: false. Bez ( ) by to byla pravda, protože [[ && ]] má větší přednost než [[ || ]]
    • [ ( a = a ) ]: syntaktická chyba, () je interpretován jako podsloupec
    • [ \( a = a -o a = b \) -a a = b ]: ekvivalent, ale (), -a a -o jsou zastaralé podle POSIX. Bez \( \) by to byla pravda, protože -a má větší přednost než -o
    • { [ a = a ] || [ a = b ]; } && [ a = b ] ekvivalent POSIX, který není zastaralý. V tomto konkrétním případě jsme však mohli napsat pouze: [ a = a ] || [ a = b ] && [ a = b ] protože || a && operátoři prostředí mají stejnou prioritu na rozdíl od [[ || ]] a [[ && ]] a -o, -a a [
  • rozdělení slov a generování názvu souboru při rozšíření (split + glob )

    • x="a b"; [[ $x = "a b" ]]: true, uvozovky nejsou potřeba
    • x="a b"; [ $x = "a b" ]: syntax chyba, rozšiřuje se na [ a b = "a b" ]
    • x="*"; [ $x = "a b" ]: syntaktická chyba, pokud je v aktuálním adresáři více než jeden soubor .
    • x="a b"; [ "$x" = "a b" ]: ekvivalent POSIX
  • =

    • [[ ab = a? ]]: true, protože odpovídá vzorům ( * ? [ jsou magické). Nerozšíří se globálně na f soubory v aktuálním adresáři.
    • [ ab = a? ]: a? glob se rozšiřuje. Může to tedy být pravda nebo nepravda v závislosti na souborech v aktuálním adresáři.
    • [ ab = a\? ]: false, ne expanze glob
    • = a == jsou stejné v [ i [[, ale == je rozšíření Bash.
    • case ab in (a?) echo match; esac: ekvivalent POSIX
    • [[ ab =~ "ab?" ]]: false, ztrácí magii s "" v Bash 3.2 a novějších a za předpokladu, že není povolena kompatibilita s bash 3.1 (jako u BASH_COMPAT=3.1)
    • [[ ab? =~ "ab?" ]]: true
  • =~

    • [[ ab =~ ab? ]]: true, POSIX rozšířeno shoda regulárního výrazu , ? nerozbaluje glob
    • [ a =~ a ]: chyba syntaxe. Žádný ekvivalent bash.
    • printf "ab\n" | grep -Eq "ab?": ekvivalent POSIX (pouze údaje o jednom řádku)
    • awk "BEGIN{exit !(ARGV[1] ~ ARGV[2])}" ab "ab?": POSIX ekvivalent.

Doporučení: vždy použijte []

Pro každý [[ ]] konstrukt, který jsem viděl, existují POSIX ekvivalenty.

Pokud používáte [[ ]] vy:

  • ztratíte přenositelnost
  • přinutí čtenáře naučit se složitosti dalšího rozšíření bash. [ je jen běžný příkaz s podivným názvem, nejde o žádnou speciální sémantiku.

Díky Stéphane Chazelas pro důležité opravy a doplňky.

Komentáře

  • @St é phaneChazelas děkuji za informace! K odpovědi jsem přidal ‚ expr výraz “ Bash ex napětí “ neznamená, že Bash byl první shell, který přidal nějakou syntaxi, učení POSIX sh vs Bash je už dost na to, aby mě pobláznilo.
  • Viz man test pokud jste zkusili man [ a ztratili se. To vysvětlí variantu POSIX.
  • Oprava: ] je argumentem k příkazu [, ale ‚ nezabrání použití dalších argumentů. ] musí být poslední argument [, ale může se vyskytnout také jako součást testovacího výrazu. Například if [ "$foo" = ] ]; then otestuje, zda je proměnná foo nastavena na „] “ (stejně jako if [ ] = "$foo" ]; then).
  • @GordonDavisson díky, ‚ t know that, fixed.
  • @ tgm1024 – Monicawasmistreated yes, that is also a valid consider.

Answer

Z bash dokumentace :

(list) seznam se provádí v prostředí subshellu (viz ENVIRONMENT PROVEDENÍ PŘÍKAZU níže). Přiřazení proměnných a integrované příkazy, které ovlivňují prostředí prostředí, nezůstanou v platnosti po dokončení příkazu. Návratový stav je stav opuštění seznamu.

Jinými slovy, zajistíte, aby vše, co se stane v „seznamu“ (jako cd), nemělo žádný účinek mimo ( a ). Jediná věc, která bude unikat, je kód ukončení posledního příkazu nebo s set -e prvním příkazem, který generuje chybu (jiný než několik, například if, while atd.)

((expression)) Výraz je vyhodnocen podle pravidel popsaných níže v části ARITMETICKÉ HODNOCENÍ. Pokud je hodnota výrazu nenulová, návratový stav je 0; jinak je návratový stav je 1. To je přesně ekvivalent k let “ výrazu „.

Toto je rozšíření bash, které vám umožňuje dělat matematiku. Je to něco podobného jako použití expr bez všech omezení expr (například mít všude mezery, uniknout * atd.)

[[ expression ]] Vrátí stav 0 nebo 1 v závislosti na vyhodnocení výrazu podmíněného výrazu. Výrazy se skládají z primárních položek popsaných níže v části PODMÍNKOVÉ VÝRAZY. Rozdělení slov a rozšíření cesty se neprovádí u slov mezi [[a]]; Provádí se expanze vlnovky, expanze parametrů a proměnných, aritmetická expanze, substituce příkazů, substituce procesů a odstraňování nabídek. Podmíněné operátory jako -f musí být bez uvozovek, aby byly rozpoznány jako primární.

Při použití s [[, < a > operátoři třídí lexikograficky podle aktuálního národního prostředí.

Nabízí pokročilý test pro porovnání řetězců, čísel a souborů trochu jako test nabídky, ale výkonnější.

[ expr ] Vrátit stav 0 (true) nebo 1 (false) v závislosti na vyhodnocení podmíněného výrazu expr. Každý operátor a operátor a musí být samostatným argumentem. Výrazy se skládají z primárních prvků popsaných výše v části PODMÍNĚNÉ VÝRAZY. test nepřijímá žádné možnosti, ani nepřijímá a ignoruje argument – jako znamení konce možností.

[…]

Ten volá test. Ve skutečnosti byl [ symbolickým odkazem na test. Funguje to stejným způsobem a máte stejná omezení. Protože binární soubor zná název, se kterým byl spuštěn, testovací program ví, kdy byl spuštěn jako [ a může ignorovat svůj poslední parametr, u kterého se očekává, že bude ]. Zábavné triky Unixu.

Upozorňujeme, že v případě bash, [ a test jsou integrované funkce (jak je uvedeno v komentáři), přesto platí stejná omezení.

Komentáře

  • Ačkoli test a [ jsou samozřejmě vestavěné příkazy v Bash, ale ‚ je pravděpodobné, že existuje také externí binární soubor.
  • Externí binární soubor pro [ není symbolickým odkazem na test ve většině moderních systémů .
  • Zdá se mi zábavné, že se obtěžují vytvořit dva samostatné binární soubory, které oba mají přesně to, co potřebují, místo toho, aby je kombinovali a přidali pár podmíněných položek. Ačkoli ve skutečnosti strings /usr/bin/test ukazuje, že obsahuje i text nápovědy, ‚ nevím, co na to říct.
  • @ Random832 Chápu váš důvod k odůvodnění GNU, abych se vyhnul neočekávanému chování arg0, ale ohledně požadavků POSIX, bych nebyl ‚ tak kladný. I když je standardně test standardně vyžadován příkaz jako samostatný souborový příkaz, nic v něm neuvádí jeho [ variantu být implementován také tímto způsobem. Například Solaris 11 neposkytuje ‚ žádný [ spustitelný soubor, ale přesto plně vyhovuje standardům POSIX
  • (výstup 1) má účinek mimo závorky.

Odpověď

Některé příklady:

Tradiční test:

foo="some thing" # check if value of foo is not empty if [ -n "$foo" ] ; then... if test -n "$foo" ; then... 

test a [ jsou příkazy jako všechny ostatní, takže proměnná je rozdělena na slova, pokud není v uvozovkách.

Nový test

[[ ... ]] je (novější) speciální konstrukce shellu, která funguje trochu jinak, nejzřejmější věcí je, že neprovádí proměnné rozdělené na slova:

if [[ -n $foo ]] ; then... 

Některé dokumentace k [ a [[ zde .

Aritmetický test:

foo=12 bar=3 if (( $foo + $bar == 15 )) ; then ... 

„Normální „commands:

Všechny výše uvedené fungují jako běžné příkazy a if může přijmout jakýkoli příkaz:

# grep returns true if it finds something if grep pattern file ; then ... 

Více příkazů:

Nebo můžeme použít více příkazů. Zabalení sady příkazů do ( ... ) je spustí v subshellu a vytvoří dočasnou kopii stavu shellu (pracovní adresář, proměnné). Pokud potřebujeme dočasně spustit nějaký program v jiném adresáři:

# this will move to $somedir only for the duration of the subshell if ( cd $somedir ; some_test ) ; then ... # while here, the rest of the script will see the new working # directory, even after the test if cd $somedir ; some_test ; then ... 

odpověď

seskupovací příkazy

Bash poskytuje dva způsoby, jak seskupit seznam příkazů, které mají být provedeny jako jednotka.

( list ) Vložení seznamu příkazů mezi závorky způsobí vytvoření prostředí subshellu a provedení každého z příkazů v seznamu v tomto subshellu. Protože seznam je provedeno v subshelmu, přiřazení proměnných nezůstanou v platnosti po dokončení subshellu.

$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a" inside: a=2 outside: a=1 

{ list; } Umístění seznam příkazů mezi složenými závorkami způsobí, že seznam bude proveden v aktuálním kontextu prostředí . Není vytvořen žádný subshell. Následující seznam středníků (nebo nových řádků) je povinný. Zdroj

${} Parameter expansion Ex: ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s $() Command substitution Ex: result=$(COMMAND) $(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

Podmíněné konstrukce

Single Bracket ie []
Pro srovnání ==, !=, <, a > a měly by být použity a pro numerické srovnání eq, ne,lt a gt je třeba použít.

Vylepšené závorky tj. [[]]

Ve všech výše uvedených příkladech jsme k uzavření podmíněného výrazu použili pouze jednotlivé závorky, ale bash umožňuje dvojité závorky, které slouží jako vylepšená verze syntaxe s jednou závorkou.

Pro srovnání ==, !=, <, a > lze použít doslovně.

  • [ je synonymum pro testovací příkaz. I když je integrován do shellu, vytváří nový proces.
  • [[ je jeho nová vylepšená verze, což je klíčové slovo, nikoli program .
  • [[ rozumí Korn a Bash.

Zdroj

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *