Jeg arbejder med Bash 3, og jeg prøver at danne en betinget. I C / C ++ er det dødt simpelt: ((A || B) && C)
. I Bash viser det sig ikke sådan (jeg tror, at Git-forfatterne må have bidraget med denne kode, før de gik videre til andre bestræbelser).
Dette fungerer ikke. Bemærk, at <0 or 1>
ikke er en streng bogstavelig; det betyder en 0 eller 1 (kommer normalt fra grep -i
).
A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi
Det resulterer i:
line 322: syntax error near unexpected token `[["
Jeg prøvede derefter:
A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi
det resulterer i:
line 322: syntax error near unexpected token `[["
En del af problemet er søgeresultaterne er de trivielle eksempler og ikke de mere komplekse eksempler med sammensatte betingelser.
Hvordan udfører jeg et simpelt ((A || B) && C)
i Bash?
Jeg er klar til bare at rulle den ud og gentage de samme kommandoer i flere blokke:
A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then ... elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then ... fi
Svar
Syntaksen for bash er ikke C-lignende, selvom en lille del af det er inspireret af C. Du kan ikke bare prøve at skrive C-kode og forvente, at den fungerer.
Hovedpunktet i en shell er at køre kommandoer. Kommandoen med åben parentes [
er en kommando, der udfører en enkelt test¹. Du kan endda skrive det som test
(uden den sidste lukkebeslag). ||
og &&
operatorer er shelloperatorer, de kombinerer kommandoer og ikke tests.
Så når du skriver
[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]
at “parses som
[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]
hvilket er det samme som
test [ "$A" -eq "0" || test "$B" -ne "0" ] && test "$C" -eq "0"
Bemærk de ubalancerede parenteser? Ja, det er ikke godt. Dit forsøg med parenteser har det samme problem: falske parenteser.
Syntaksen til gruppekommandoer sammen er parenteser. Den måde, hvorpå parenteser analyseres, kræver en komplet kommando foran dem, så du bliver nødt til at afslutte kommandoen inde i selerne med en ny linje eller semikolon.
if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then …
“er en alternativ måde at bruge dobbelt parentes. I modsætning til enkelte parenteser er dobbelte parenteser speciel shell-syntaks. De afgrænser betingede udtryk . Inde i dobbelte parenteser kan du bruge parenteser og operatorer som &&
og ||
. Da de dobbelte parenteser er shell-syntaks, ved shell, at når disse operatorer er inden for parenteser, er de “en del af den betingede udtrykssyntaks, ikke en del af den almindelige shell-kommandosyntaks.
Hvis alle dine tests er numeriske, er der endnu en anden måde, der afgrænser artihmetiske udtryk . Aritmetiske udtryk udfører heltalberegninger med en meget C-lignende syntaks.
if (((A == 0 || B != 0) && C == 0)); then …
Du kan finde min bash-beslag primer nyttigt.
[
kan bruges i almindelig sh. [[
og ((
er specifikke for bash (og ksh og zsh).
¹ Det kan også kombinere flere tests med boolske operatører, men dette er besværligt at bruge og har subtile faldgruber, så jeg forklarer det ikke.
Kommentarer
Svar
Brug [[
:
if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...
Hvis du foretrækker [
, fungerer følgende:
if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...
Kommentarer
- Tak, Stephen. I mit tilfælde brugte jeg dit første eksempel således … regex = ‘ ^ [0-9] + $ ‘ length = $ {#datearg} hvis! [[$ datearg = ~ $ regex & & $ længde -ekv 8]]; derefter ekko ” fejl: Ikke et antal lenth af 8 “; fi
Svar
Brug -o
operatoren i stedet for din indlejret ||. Du kan også bruge -a
til at erstatte & & hvis det er nødvendigt i dine andre udsagn .
EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true if [ "$A" -eq "0" -o "$B" -ne "0" ] && [ "$C" -eq "0" ]; then echo success;fi
Kommentarer
- Tak. Jeg stødte på
-a
og-o
, men jeg eksperimenterede ikke med dem. En person på Stack Overflow sagde, at han skulle undgå det. Jeg var for det meste enig med dem, da scriptet er mindre læsbart ved hjælp af dem. - … men mere bærbare.
- @Kusalananda – Tak for heads-ups til bærbarhed. Scriptet skal køre på systemer med Bash 2 til Bash 4. Har
[[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]
problemer med dem? - Der er ingen problemer, så længe du holder
bash
eller enhver anden skal, der forstår[[ ... ]]
. - Undersiden af at bruge -a er, at den ikke ‘ t kortslutning, hvis det første udtryk er falsk. Så hvis du stoler på kortslutning for at forhindre, at et potentielt fatalt 2. udtryk kører, kan du ikke bruge -a. Eksempel: pastebin.com/zM77TXW1
[[ … ]]
blev tilføjet i bash 2.02.((…))
blev tilføjet i bash 2.0.||
og&&
skift fra[
til[[
og((
. Lige forrang i[
(brug parentes til at kontrollere rækkefølgen af evalueringen), men & & har højere prioritet i[[
og((
end||
(som i C).[[ … ]]
eller$((…))
er kun til gruppering.