Wat is het verschil tussen de Bash-operators [[vs [vs (vs ((?

) Ik ben een beetje in de war over wat deze operators anders doen als gebruikt in bash (haakjes, dubbele haakjes, haakjes en dubbele haakjes).

[[ , [ , ( , (( 

Ik heb gezien dat mensen ze gebruiken voor als uitspraken als deze:

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

Reacties

  • Gerelateerd: met enkele of dubbele haakjes – bash
  • Haakjes en haakjes zijn ‘ niet zo gemakkelijk te zoeken in documentatie, en dat ‘ is alles wat je hebt als je de namen van die functies niet ‘ kent.

Antwoord

In Bourne-achtige shells ziet een if -instructie er doorgaans uit als

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

De then -clausule wordt uitgevoerd als de afsluitcode van de lijst met commandos is nul. Als de afsluitcode niet nul is, wordt de clausule else uitgevoerd. command-list1 kan eenvoudig of complex zijn. Het kan bijvoorbeeld een reeks van een of meer pijplijnen zijn, gescheiden door een van de operatoren ;, &, &&, || of nieuwe regel. De if voorwaarden die hieronder worden weergegeven, zijn slechts speciale gevallen van command-list1:

  1. if [ condition ]

    [ is een andere naam voor het traditionele test commando. [ / test is een standaard POSIX-hulpprogramma. Alle POSIX-shells hebben het ingebouwd (hoewel dat “niet vereist is voor POSIX²). Het test commando stelt een afsluitcode in en het if statement handelt dienovereenkomstig. Typische tests zijn of een bestand bestaat of dat het ene nummer gelijk is aan het andere.

  2. if [[ condition ]]

    Dit is een nieuwe verbeterde variant op test ¹ van ksh die bash , zsh , yash , busybox sh ondersteunen ook. Deze [[ ... ]] constructie stelt ook een exitcode in en de if -instructie handelt dienovereenkomstig. Onder zijn uitgebreide functies kan het testen of een tekenreeks overeenkomt met een jokertekenpatroon (niet in busybox sh ).

  3. if ((condition))

    Nog een ksh extensie die bash en zsh ook ondersteunen. Dit voert rekenkundige bewerkingen uit. Als resultaat van de rekenkundige bewerkingen wordt een exitcode ingesteld en werkt de instructie if acco rdingly. Het retourneert een afsluitcode van nul (waar) als het resultaat van de rekenkundige berekening niet nul is. Net als [[...]] is dit formulier niet POSIX en daarom niet draagbaar.

  4. if (command)

    Dit voert het commando uit in een subshell. Wanneer het commando is voltooid, stelt het een afsluitcode in en de if -instructie handelt overeenkomstig.

    Een typische reden voor het gebruik van een dergelijke subshell is om de bijwerkingen van command if command vereiste variabeletoewijzingen of andere veranderingen in de shell-omgeving. Dergelijke veranderingen blijven niet bestaan nadat de subshell is voltooid.

  5. if command

    commando wordt uitgevoerd en de if instructie werkt volgens zijn exitcode.


¹ hoewel het niet echt een commando is, maar een speciale shell-constructie met een eigen syntaxis die gescheiden is van die van een normaal commando, en aanzienlijk variëren tussen shell-implementaties

² POSIX vereist wel dat er een standalone test en [ hulpprogrammas op het systeem, hoewel in het geval van [ bekend is dat verschillende Linux-distributies m het uitgeven.

Reacties

  • Bedankt voor het opnemen van de 5e optie. De sleutel van ‘ om te begrijpen hoe dit werkelijk werkt en wordt verrassend genoeg onderbenut.
  • Merk op dat [ eigenlijk een binair, geen intern commando of symbool. Woont over het algemeen in /bin.
  • @JulienR. eigenlijk is [ ingebouwd, net als test. Om compatibiliteitsredenen zijn er binaire versies beschikbaar. Bekijk help [ en help test.
  • Het is vermeldenswaard dat while ((isnt POSIX, $(( dwz rekenkundige uitbreiding is en het is ‘ s gemakkelijk om ze te verwarren. Vaak is een tijdelijke oplossing het gebruik van iets als [ $((2+2)) -eq 4 ] gebruik maken van rekenkunde in conditinale uitspraken
  • Ik wou dat ik dit antwoord meer dan eens kon stemmen. Perfecte uitleg.

Antwoord

  • (…) haakjes geven een subshell . Wat erin zit, is geen uitdrukking zoals in veel andere talen. Het is een lijst met commandos (net als tussen haakjes). Deze commandos worden uitgevoerd in een apart subproces, dus elke omleiding, toewijzing, etc. uitgevoerd binnen de haakjes heeft geen effect buiten de haakjes.
    • Met een voorlooptijd dollarteken, $(…) is een commandosubstitutie : er is een commando tussen de haakjes en de uitvoer van het commando wordt gebruikt als onderdeel van de opdrachtregel (na extra uitbreidingen tenzij de vervanging tussen dubbele aanhalingstekens staat, maar dat is “s een ander verhaal ).
  • { … } accolades zijn als haakjes in de zin dat ze commandos groeperen, maar ze beïnvloeden alleen het parseren, niet het groeperen. Het programma x=2; { x=4; }; echo $x drukt er 4 af, terwijl x=2; (x=4); echo $x er 2 afdrukt. (Ook accolades die trefwoorden zijn, moeten worden gescheiden en gevonden in opdrachtpositie (vandaar de spatie na { en de ; voor }) terwijl haakjes zijn niet “t. Dat is gewoon een syntaxis.)
    • Met een voorlopend dollarteken is ${VAR} een parameteruitbreiding , uitbreidend naar de waarde van een variabele, met mogelijke extra transformaties. De ksh93 shell ondersteunt ook ${ cmd;} als een vorm van opdrachtvervanging die geen “subshell” voortbrengt.
  • ((…)) dubbele haakjes omringen een rekenkundige instructie , dat wil zeggen een berekening op gehele getallen, met een syntaxis die lijkt op andere programmeertalen. Deze syntaxis wordt meestal gebruikt voor opdrachten en in conditionals. Deze bestaat alleen in ksh / bash / zsh, niet in plain sh.
    • Dezelfde syntaxis wordt gebruikt in rekenkundige uitdrukkingen $((…)), die zich uitbreiden naar de gehele waarde van de uitdrukking.
  • [ … ] enkele haakjes omringen voorwaardelijke expressies . Voorwaardelijke expressies worden meestal gebouwd op operators , zoals -n "$variable" om te testen of een variabele leeg is en -e "$file" om te testen of er een bestand bestaat. Houd er rekening mee dat u een spatie rond elk operator (bijv. [ "$x" = "$y" ], niet [ "$x"="$y" ] ), en een spatie of een teken zoals ; zowel binnen als buiten de haakjes (bijv. [ -n "$foo" ], niet [-n "$foo"] ).
  • [[ … ]] dubbele haakjes zijn een alternatieve vorm van voorwaardelijke uitdrukkingen in ksh / bash / zsh met een paar extra functies, je kunt bijvoorbeeld om te testen of een bestand een symbolische link naar een normaal bestand is, terwijl voor enkele haakjes [ -L "$file" ] && [ -f "$file" ] nodig is. Zie Waarom werkt parameteruitbreiding met spaties zonder aanhalingstekens tussen dubbele haakjes [[maar geen enkele haakjes [? voor meer informatie over dit onderwerp.

In de shell is elk commando een voorwaardelijk commando: elk commando heeft een retourstatus die ofwel 0 is voor succes of een geheel getal tussen 1 en 255 (en mogelijk meer in sommige shells) wat aangeeft mislukking. Het [ … ] commando (of [[ … ]] syntaxisformulier) is een bepaald commando dat ook kan worden gespeld als test … en slaagt wanneer een bestand bestaat, of wanneer een string niet leeg is, of wanneer een getal kleiner is dan een ander, enz. De ((…)) syntaxisvorm slaagt wanneer een getal niet nul is .Hier zijn een paar voorbeelden van conditionals in een shellscript:

  • Test of myfile de string hello:

    if grep -q hello myfile; then … 
  • Als mydir een directory is, ga dan naar het en doe dingen:

    if cd mydir; then echo "Creating mydir/myfile" echo "some content" >myfile else echo >&2 "Fatal error. This script requires mydir to exist." fi 
  • Test of er een bestand is met de naam myfile in de huidige directory:

    if [ -e myfile ]; then … 
  • Hetzelfde, maar ook inclusief hangende symbolische links:

    if [ -e myfile ] || [ -L myfile ]; then … 
  • Test of de waarde van x (waarvan wordt aangenomen dat deze numeriek is) ten minste 2 is, draagbaar:

    if [ "$x" -ge 2 ]; then … 
  • Test of de waarde van x (waarvan wordt aangenomen dat deze numeriek is) is ten minste 2, in bash / ksh / zsh:

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

Reacties

  • Houd er rekening mee dat enkele haakjes de -a ondersteunen in plaats van &&, zodat men kan schrijven: [ -L $file -a -f $file ], wat hetzelfde aantal tekens tussen de haakjes is zonder de extra [ en ]
  • @AlexisWilke De operatoren -a en -o zijn problematisch omdat ze kunnen leiden tot onjuiste parses als sommige van de betrokken operanden op operators lijken. Dat ‘ is waarom ik ze niet ‘ noem: ze hebben geen voordeel en ‘ t werkt altijd. En schrijf nooit uitbreidingen van variabelen zonder aanhalingstekens zonder een goede reden: [[ -L $file -a -f $file ]] is prima, maar met enkele haakjes heb je [ -L "$file" -a -f "$file" ] nodig (wat bijvoorbeeld ok is als $file begint altijd met / of ./).
  • Merk op dat it ‘ s [[ -L $file && -f $file ]] (geen -a met de [[...]] variant).

Antwoord

[ vs [[

Dit antwoord behandelt de [ vs [[ subset van de vraag.

Enkele verschillen op Bash 4.3.11:

  • POSIX versus Bash-extensie:

  • normaal commando versus magie

    • [ is gewoon een gewoon commando met een rare naam.

      ] is slechts het laatste argument van [.

    Ubuntu 16.04 heeft eigenlijk een uitvoerbaar bestand op /usr/bin/[ geleverd door coreutils , maar de ingebouwde bash-versie heeft voorrang.

    Er is niets veranderd aan de manier waarop Bash het commando parseert.

    In het bijzonder < is omleiding, && en || voegen meerdere opdrachten samen, ( ) genereert subshells tenzij ontsnapt door \, en woorduitbreiding gebeurt zoals gewoonlijk.

    • [[ X ]] is een enkele constructie die ervoor zorgt dat X op magische wijze wordt geparseerd. <, &&, || en () worden speciaal behandeld en regels voor het splitsen van woorden zijn anders.

      Er zijn ook andere verschillen zoals = en =~ .

    In Bashese: [ is een ingebouwd commando, en [[ is een trefwoord: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && en ||

    • [[ a = a && b = b ]]: waar, logisch en
    • [ a = a && b = b ]: syntaxisfout, && geparseerd als een EN-opdrachtscheidingsteken cmd1 && cmd2
    • [ a = a ] && [ b = b ]: POSIX betrouwbaar equivalent
    • [ a = a -a b = b ]: bijna equivalent, maar verouderd door POSIX omdat het krankzinnig is en mislukt voor sommige waarden van a of b zoals ! of ( wat zou worden geïnterpreteerd als logische operaties
  • (

    • [[ (a = a || a = b) && a = b ]]: false. Zonder ( ) zou dit waar zijn omdat [[ && ]] een grotere prioriteit heeft dan [[ || ]]
    • [ ( a = a ) ]: syntaxisfout, () wordt geïnterpreteerd als een subshell
    • [ \( a = a -o a = b \) -a a = b ]: equivalent, maar (), -a en -o zijn verouderd door POSIX. Zonder \( \) zou waar zijn omdat -a een grotere prioriteit heeft dan -o
    • { [ a = a ] || [ a = b ]; } && [ a = b ] niet-verouderd POSIX-equivalent. In dit specifieke geval hadden we echter alleen kunnen schrijven: [ a = a ] || [ a = b ] && [ a = b ] omdat de || en && shell-operators hebben dezelfde prioriteit in tegenstelling tot [[ || ]] en [[ && ]] en -o, -a en [
  • woordsplitsing en het genereren van bestandsnamen bij uitbreidingen (split + glob )

    • x="a b"; [[ $x = "a b" ]]: waar, aanhalingstekens niet nodig
    • x="a b"; [ $x = "a b" ]: syntaxis fout, breidt uit naar [ a b = "a b" ]
    • x="*"; [ $x = "a b" ]: syntaxisfout als er meer dan één bestand in de huidige map is .
    • x="a b"; [ "$x" = "a b" ]: POSIX-equivalent
  • =

    • [[ ab = a? ]]: true, omdat het patroonovereenkomst ( * ? [ zijn magisch). Wordt niet globaal uitgevouwen naar f iles in de huidige directory.
    • [ ab = a? ]: a? glob breidt uit. Dus kan waar of onwaar zijn, afhankelijk van de bestanden in de huidige directory.
    • [ ab = a\? ]: false, niet glob uitbreiding
    • = en == zijn hetzelfde in [ en [[, maar == is een Bash-extensie.
    • case ab in (a?) echo match; esac: POSIX-equivalent
    • [[ ab =~ "ab?" ]]: false, verliest magie met "" in Bash 3.2 en hoger en mits compatibiliteit met bash 3.1 niet is ingeschakeld (zoals met BASH_COMPAT=3.1)
    • [[ ab? =~ "ab?" ]]: true
  • =~

    • [[ ab =~ ab? ]]: true, POSIX uitgebreid reguliere expressie overeenkomst, ? breidt niet globaal uit
    • [ a =~ a ]: syntaxisfout. Geen bash-equivalent.
    • printf "ab\n" | grep -Eq "ab?": POSIX-equivalent (alleen gegevens van één regel)
    • awk "BEGIN{exit !(ARGV[1] ~ ARGV[2])}" ab "ab?": POSIX-equivalent.

Aanbeveling: gebruik altijd []

Er zijn POSIX-equivalenten voor elk [[ ]] construct dat ik heb gezien.

Als je [[ ]] gebruikt:

  • verlies je draagbaarheid
  • dwing je de lezer om de fijne kneepjes van een andere bash-extensie te leren. [ is gewoon een gewoon commando met een rare naam, er is geen speciale semantiek bij betrokken.

Met dank aan Stéphane Chazelas voor belangrijke correcties en toevoegingen.

Reacties

  • @St é phaneChazelas bedankt voor de info! Ik ‘ heb expr toegevoegd aan het antwoord. De term ” Bash ex spanning ” wil niet zeggen dat Bash de eerste shell was die wat syntaxis toevoegde, het leren van POSIX sh vs Bash is al genoeg om me gek te maken.
  • Zie man test als je man [ probeerde en verdwaald bent. Dat verklaart de POSIX-variant.
  • Correctie: ] is een argument voor het [ commando, maar het doet niet ‘ t voorkomen dat verdere argumenten worden gebruikt. ] moet het laatste argument zijn voor [, maar het kan ook voorkomen als onderdeel van de testuitdrukking. if [ "$foo" = ] ]; then zal bijvoorbeeld testen of de variabele foo is ingesteld op “] ” (net als if [ ] = "$foo" ]; then).
  • @GordonDavisson bedankt, ik heb ‘ weet dat niet, opgelost.
  • @ tgm1024 – Monicawasmishandated ja, dat is ook een geldige overweging.

Antwoord

Van de bash-documentatie :

(list) lijst wordt uitgevoerd in een subshell-omgeving (zie COMMANDO-UITVOERINGSOMGEVING hieronder). Variabele toewijzingen en ingebouwde commandos die de omgeving van de shell beïnvloeden, blijven niet van kracht nadat het commando is voltooid. De retourstatus is de exit-status van de lijst.

Met andere woorden, u zorgt ervoor dat wat er ook gebeurt in “list” (zoals een cd) geen effect heeft buiten de ( en ). Het enige dat zal lekken, is de afsluitcode van de laatste opdracht of met set -e de eerste opdracht die een fout genereert (andere dan een paar, zoals if, while, etc.)

((expression)) De expressie wordt geëvalueerd volgens de regels die hieronder worden beschreven onder ARITMETISCHE EVALUATIE. Als de waarde van de expressie niet nul is, is de retourstatus 0; anders de retourstatus is 1. Dit is exact gelijk aan ” expressie “.

Dit is een bash-extensie waarmee je wiskunde kunt doen. Dit lijkt enigszins op het gebruik van expr zonder alle beperkingen van expr (zoals overal spaties hebben, ontsnappen aan *, etc.)

[[ expression ]] Retourneer een status van 0 of 1 afhankelijk van de evaluatie van de uitdrukking voor voorwaardelijke expressie. Uitdrukkingen zijn samengesteld uit de primaire kleuren die hieronder worden beschreven onder VOORWAARDELIJKE UITDRUKKINGEN. Woordsplitsing en padnaamuitbreiding worden niet uitgevoerd op de woorden tussen de [[en]]; tilde-uitbreiding, parameter- en variabele-uitbreiding, rekenkundige uitbreiding, opdrachtvervanging, procesvervanging en citaatverwijdering worden uitgevoerd. Voorwaardelijke operatoren zoals -f mogen niet worden aangehaald om als primair te worden herkend.

Bij gebruik met [[, de < en > operators sorteren lexicografisch volgens de huidige locale.

Dit biedt een geavanceerde test om strings, getallen en bestanden een beetje te vergelijken met test aanbiedingen, maar krachtiger.

[ expr ] Retourneer een status van 0 (true) of 1 (false), afhankelijk van de evaluatie van de voorwaardelijke expressie expr. Elke operator en oper en moeten een afzonderlijk argument zijn. Expressies zijn samengesteld uit de voorverkiezingen die hierboven zijn beschreven onder VOORWAARDELIJKE EXPRESSIES. test accepteert geen enkele optie, noch accepteert en negeert het een argument van – als aanduiding van het einde van opties.

[…]

Deze roept test aan. Eigenlijk was [ vroeger een symbolische link naar test. Het werkt op dezelfde manier en je hebt dezelfde beperkingen. Aangezien een binair bestand de naam kent waarmee het is gestart, weet het testprogramma wanneer het is gestart als [ en kan het de laatste parameter negeren, die naar verwachting ]. Leuke Unix-trucs.

Merk op dat in het geval van bash, [ en test zijn ingebouwde functies (zoals vermeld in een opmerking), maar vrijwel dezelfde beperkingen zijn van toepassing.

Opmerkingen

  • Hoewel test en [ zijn natuurlijk ingebouwde opdrachten in Bash, maar ‘ is waarschijnlijk een extern binair bestand bestaat ook.
  • Het externe binaire bestand voor [ is geen symbolische link naar test op de meeste moderne systemen .
  • Op de een of andere manier vind ik het grappig dat ze de moeite nemen om twee aparte binaire bestanden te maken, die allebei precies hebben wat ze nodig hebben, in plaats van ze alleen te combineren en een paar voorwaarden toe te voegen. Hoewel strings /usr/bin/test laat zien dat het ook de helptekst heeft, dus ik weet niet ‘ wat ik moet zeggen.
  • @ Random832 Ik begrijp uw punt over de GNU-grondgedachte om onverwacht arg0-gedrag te vermijden, maar over POSIX-vereisten zou ik ‘ niet zo bevestigend zijn. Hoewel de test -opdracht uiteraard door de standaard vereist is om te bestaan als een op zichzelf staande bestandsgebaseerde opdracht, staat er niets in dat de [ -variant moet bestaan ook op die manier worden geïmplementeerd. Solaris 11 biedt bijvoorbeeld geen ‘ t een [ uitvoerbaar bestand, maar is niettemin volledig in overeenstemming met de POSIX-standaarden
  • (exit 1) heeft een effect buiten de haakjes.

Answer

Enkele voorbeelden:

Traditionele test:

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

test en [ zijn commandos zoals alle andere, dus de variabele wordt opgesplitst in woorden, tenzij deze tussen aanhalingstekens staat.

Test in nieuwe stijl

[[ ... ]] is een (nieuwere) speciale shell-constructie, die een beetje anders werkt, het meest voor de hand liggende is dat het geen variabelen voor woordsplitsing bevat:

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

Sommige documentatie over [ en [[ hier .

Rekenkundige test:

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

“Normaal “commands:

Alle bovenstaande werken als normale commandos, en if kan elk commando aannemen:

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

Meerdere opdrachten:

Of we kunnen meerdere commandos gebruiken. Door een set commandos in ( ... ) te plaatsen, worden ze in een subshell uitgevoerd, waardoor een tijdelijke kopie van de staat van de shell wordt gemaakt (werkmap, variabelen). om een programma tijdelijk in een andere map uit te voeren:

# 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 ... 

Antwoord

Groepeeropdrachten

Bash biedt twee manieren om een lijst met opdrachten te groeperen die als een eenheid moeten worden uitgevoerd.

( list ) Door een lijst met commandos tussen haakjes te plaatsen, wordt een subshell-omgeving gemaakt en wordt elk van de commandos in de lijst in die subshell uitgevoerd. uitgevoerd in een subshell, blijven variabeletoewijzingen niet van kracht nadat de subshell is voltooid.

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

{ list; } Een lijst met opdrachten tussen accolades zorgt ervoor dat de lijst wordt uitgevoerd in de huidige shell-context . Er wordt geen subshell gemaakt. De volgende lijst met puntkommas (of nieuwe regel) is vereist. Bron

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

Conditionele constructies

Enkele haakjes ie []
Ter vergelijking ==, !=, <, en > en moeten worden gebruikt en voor numerieke vergelijking eq, ne,lt en gt moet worden gebruikt.

Enhanced Brackets ie [[]]

In alle bovenstaande voorbeelden hebben we alleen enkele haakjes gebruikt om de voorwaardelijke uitdrukking te omsluiten, maar bash staat dubbele haakjes toe die dienen als een verbeterde versie van de syntaxis met enkele haakjes.

Ter vergelijking kunnen ==, !=, <, en > letterlijk worden gebruikt.

  • [ is een synoniem voor testopdracht. Zelfs als het in de shell is ingebouwd, creëert het een nieuw proces.
  • [[ is een nieuwe verbeterde versie ervan, wat een trefwoord is, geen programma .
  • [[ wordt begrepen door Korn en Bash.

Bron

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *