Mi chiedevo solo quale fosse esattamente la differenza tra
[[ $STRING != foo ]]
e
[ $STRING != foo ]
è, a parte questo, che è conforme a posix, trovato in sh e il primo è un'estensione trovata in bash.
Mi chiedevo solo quale fosse esattamente la differenza tra
[[ $STRING != foo ]]
e
[ $STRING != foo ]
è, a parte questo, che è conforme a posix, trovato in sh e il primo è un'estensione trovata in bash.
Risposte:
Ci sono diverse differenze. Secondo me, alcuni dei più importanti sono:
[
è incorporato in Bash e in molte altre conchiglie moderne. Il builtin [
è simile al test
requisito aggiuntivo di una chiusura ]
. I builtin [
e test
imitano la funzionalità /bin/[
e /bin/test
insieme ai loro limiti in modo che gli script siano retrocompatibili. Gli eseguibili originali esistono ancora principalmente per conformità POSIX e compatibilità con le versioni precedenti. L'esecuzione del comando type [
in Bash indica che [
viene interpretato come predefinito per impostazione predefinita. (Nota: which [
cerca solo gli eseguibili sul PERCORSO ed è equivalente a type -p [
)[[
non è così compatibile, non funzionerà necessariamente con qualsiasi /bin/sh
punto. Quindi [[
è la più moderna opzione Bash / Zsh / Ksh.[[
è incorporato nella shell e non ha requisiti legacy, non è necessario preoccuparsi della divisione delle parole in base alla variabile IFS per confondere le variabili che valutano una stringa con spazi. Pertanto, non è necessario inserire la variabile tra virgolette doppie.Per la maggior parte, il resto è solo una sintassi migliore. Per vedere più differenze, consiglio questo link a una risposta alle domande frequenti: qual è la differenza tra test, [e [[? . In effetti, se prendi sul serio lo script bash, ti consiglio di leggere l'intero wiki , comprese le FAQ, le insidie e la guida. La sezione test della sezione guida spiega anche queste differenze e perché gli autori pensano che [[
sia una scelta migliore se non devi preoccuparti di essere portatile. Le ragioni principali sono:
< >
alle barre rovesciate per evitare che vengano valutate come reindirizzamento di input, che può davvero rovinare alcune cose sovrascrivendo i file. Questo torna ad [[
essere incorporato. Se [(test) è un programma esterno, la shell dovrebbe fare un'eccezione nel modo in cui valuta <
e >
solo se /bin/test
viene chiamata, il che non avrebbe davvero senso.In breve:
[è un builth bash
[[]] sono parole chiave bash
Parole chiave: le parole chiave sono abbastanza simili ai builtin, ma la differenza principale è che a loro si applicano regole di analisi speciali. Ad esempio, [è un built-in bash, mentre [[è una parola chiave bash. Sono entrambi usati per testare le cose, ma poiché [[è una parola chiave anziché un built-in, trae vantaggio da alcune regole di analisi speciali che lo rendono molto più semplice:
$ [ a < b ]
-bash: b: No such file or directory
$ [[ a < b ]]
Il primo esempio restituisce un errore perché bash tenta di reindirizzare il file b al comando [a]. Il secondo esempio in realtà fa quello che ti aspetti. Il carattere <non ha più il suo significato speciale di operatore Reindirizzamento file.
Fonte: http://mywiki.wooledge.org/BashGuide/CommandsAndArguments
[
è un comando shell POSIX; non è necessario che sia incorporato. ]
è solo un argomento che quel comando cerca, in modo che la sintassi sia bilanciata. Il comando è sinonimo di test
tranne che test
non cerca una chiusura ]
.
Differenze comportamentali
Alcune differenze su Bash 4.3.11:
Estensione POSIX vs Bash:
[
è POSIX[[
è un'estensione di Bash¹ documentata su: https://www.gnu.org/software/bash/manual/bash.html#Conditional-Constructscomando regolare vs magia
[
è solo un comando regolare con un nome strano.
]
è solo un argomento [
che impedisce l'utilizzo di ulteriori argomenti.
Ubuntu 16.04 in realtà ha un eseguibile per esso /usr/bin/[
fornito da coreutils, ma la versione integrata di bash ha la precedenza.
Nulla è alterato nel modo in cui Bash analizza il comando.
In particolare, <
è il reindirizzamento &&
e ||
concatena più comandi, ( )
genera sottotitoli a meno che non sia evaso da \
, e l'espansione delle parole avviene come al solito.
[[ X ]]
è un singolo costrutto che consente di X
analizzarlo magicamente. <
, &&
, ||
E ()
sono trattati in modo speciale, e le regole suddivisione in parole sono diverse.
Ci sono anche ulteriori differenze come =
e =~
.
In bashese: [
è un comando integrato ed [[
è una parola chiave: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword
<
[[ a < b ]]
: confronto lessicografico[ a \< b ]
: Come sopra. \
richiesto altrimenti esegue il reindirizzamento come per qualsiasi altro comando. Estensione Bash.expr a \< b > /dev/null
: POSIX equivalente², consultare: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989&&
e ||
[[ a = a && b = b ]]
: vero, logico e[ a = a && b = b ]
: errore di sintassi, &&
analizzato come separatore di comandi ANDcmd1 && cmd2
[ a = a -a b = b ]
: equivalente, ma deprecato da POSIX³[ a = a ] && [ b = b ]
: POSIX ed equivalente affidabile(
[[ (a = a || a = b) && a = b ]]
: falso[ ( a = a ) ]
: errore di sintassi, ()
viene interpretato come una subshell[ \( a = a -o a = b \) -a a = b ]
: equivalente, ma ()
è deprecato da POSIX{ [ a = a ] || [ a = b ]; } && [ a = b ]
POSIX equivalente 5suddivisione delle parole e generazione del nome del file in caso di espansioni (split + glob)
x='a b'; [[ $x = 'a b' ]]
: vero, virgolette non necessariex='a b'; [ $x = 'a b' ]
: errore di sintassi, si espande in [ a b = 'a b' ]
x='*'; [ $x = 'a b' ]
: errore di sintassi se c'è più di un file nella directory corrente.x='a b'; [ "$x" = 'a b' ]
: Equivalente POSIX=
[[ ab = a? ]]
: vero, perché corrisponde al modello ( * ? [
sono magici). Glob non si espande nei file nella directory corrente.[ ab = a? ]
: a?
glob si espande. Quindi può essere vero o falso a seconda dei file nella directory corrente.[ ab = a\? ]
: false, non espansione globale=
e ==
sono uguali in entrambi [
e [[
, ma ==
è un'estensione di Bash.case ab in (a?) echo match; esac
: Equivalente POSIX[[ ab =~ 'ab?' ]]
: false 4 , perde la magia con''
[[ ab? =~ 'ab?' ]]
: vero=~
[[ ab =~ ab? ]]
: true, la corrispondenza delle espressioni regolari estese POSIX ?
non si espande a livello globale[ a =~ a ]
: Errore di sintassi. Nessun equivalente bash.printf 'ab\n' | grep -Eq 'ab?'
: Equivalente POSIX (solo dati a linea singola)awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?'
: Equivalente POSIX.Raccomandazione : usare sempre []
.
Esistono equivalenti POSIX per ogni [[ ]]
costrutto che ho visto.
Se ti usi [[ ]]
:
[
è solo un comando regolare con un nome strano, nessuna semantica speciale è coinvolta.¹ Ispirato al [[...]]
costrutto equivalente nella shell Korn
² ma non riesce per alcuni valori di a
o b
(come +
o index
) e fa un confronto numerico se a
e b
sembra numeri decimali. expr "x$a" '<' "x$b"
funziona intorno a entrambi.
³ e fallisce anche per alcuni valori di a
o b
come !
o (
.
4 in bash 3.2 e versioni successive e la compatibilità fornita con bash 3.1 non è abilitata (come con BASH_COMPAT=3.1
)
5 se il raggruppamento (qui con il {...;}
gruppo di comando anziché (...)
che sarebbe in una subshell inutile) non è necessaria in quanto i ||
e &&
operatori guscio (diversamente le ||
e &&
[[...]]
operatori oi -o
/ -a
[
operatori) hanno uguale precedenza. Quindi [ a = a ] || [ a = b ] && [ a = b ]
sarebbe equivalente.
printf 'ab' | grep -Eq 'ab?'
all'interno if [ … ]
?
if ( printf 'ab' | grep -Eq 'a' ); then echo 'a'; fi
. []
è un comando proprio come grep
. La ()
non può essere necessario in questo comando non sono sicuro: ho aggiunto che a causa della |
, dipende da come Bash analizza le cose. Se non ci fosse, |
sono sicuro che puoi scrivere solo if cmd arg arg; then
.
()
sembra: stackoverflow.com/questions/8965509/...
La singola parentesi cioè []
è conforme alla shell POSIX per racchiudere un'espressione condizionale.
Le doppie parentesi cioè [[]]
sono una versione migliorata (o estensione) della versione POSIX standard, supportata da bash e altre shell (zsh, ksh).
In bash, per il confronto numerico utilizzato eq
, ne
, lt
e gt
, con doppie parentesi quadre per il confronto possiamo usare ==
, !=
, <,
e >
letteralmente.
[
è sinonimo di comando test. Anche se è integrato nella shell, crea un nuovo processo.[[
è una nuova versione migliorata, che è una parola chiave, non un programma. per esempio:
[ var1 lt var2] #works
[ var1 < var2] #error: var2 No such file or directory
[ var1 \< var2] #works with escape
[[ var1 < var2]] #works
if
dichiarazione, vedi mywiki.wooledge.org/BashPitfalls#if_.5Bgrep_foo_myfile.5D