sviluppo-web-qa.it

Qual è la differenza tra parentesi quadre doppie e singole 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.

451
0x89

Ci sono diverse differenze. Secondo me, alcuni dei più importanti sono:

  1. [ è integrato in Bash e in molte altre shell moderne. The builtin [ è simile a test con il requisito aggiuntivo di una chiusura ]. The builtins [ 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. 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 [)
  2. [[ non è così compatibile, non funzionerà necessariamente con qualunque /bin/sh punta a. Così [[ è il più moderno Bash/Zsh/Ksh.
  3. Perché [[ è integrato in Shell e non ha requisiti legacy, non è necessario preoccuparsi della suddivisione in Word basata su [~ # ~] ifs [~ # ~] variabile da rovinare su 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 FAQ risposta: Qual è la differenza tra test, [e [[? . In effetti, se sei serio sullo script bash, ti consiglio di leggere l'intero wiki , comprese le FAQ, Insidie e Guida. La sezione test dalla sezione guida spiega questi differenze, e perché gli autori pensano [[ è una scelta migliore se non devi preoccuparti di essere portatile. Le ragioni principali sono:

  1. Non devi preoccuparti di citare il lato sinistro del test in modo che venga effettivamente letto come variabile.
  2. Non devi scappare di meno e di più di < > con barre rovesciate per evitare che vengano valutate come reindirizzamento di input, che può davvero rovinare alcune cose sovrascrivendo i file. Questo risale a [[ essendo incorporato. Se [(test) è un programma esterno, Shell dovrebbe fare un'eccezione nel modo in cui valuta < e > solo se /bin/test viene chiamato, il che non avrebbe davvero senso.
325
Kyle Brandt

In breve:

[è un bash Builtin

[[]] sono bash Parole chiave

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, beneficia di 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

138
abhiomkar

Differenze di comportamento

Alcune differenze su Bash 4.3.11:

  • Estensione POSIX vs Bash:

  • comando regolare vs magia

    • [ È solo un comando regolare con un nome strano.

      ] È solo un argomento di [ Che impedisce l'utilizzo di ulteriori argomenti.

      Ubuntu 16.04 ha in realtà un eseguibile per /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 || Concatenano più comandi, ( ) Genera sottotitoli a meno che non sfuggano a \ E l'espansione di Word succede come al solito.

    • [[ X ]] È un singolo costrutto che consente di analizzare magicamente X. <, &&, || E () Sono trattati in modo speciale e le regole di suddivisione delle parole sono diverse.

      Ci sono anche altre differenze come = E =~.

      In bashese: [ È un comando incorporato e [[ È una parola chiave: https://askubuntu.com/questions/445749/whats-the-difference-b Between -shell-builtin-e-Shell-parola chiave

  • <

  • && E ||

    • [[ a = a && b = b ]]: Vero, logico e
    • [ a = a && b = b ]: Errore di sintassi, && Analizzato come separatore di comandi AND cmd1 && 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 ]]: false
    • [ ( 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 equivalente5
  • Suddivisione delle parole e generazione del nome del file in caso di espansioni (split + glob)

    • x='a b'; [[ $x = 'a b' ]]: Vero, virgolette non necessarie
    • x='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é lo fa pattern matching (* ? [ 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\? ]: Falso, non espansione globale
    • = E == Sono gli stessi in [ E [[, Ma == È un'estensione Bash.
    • case ab in (a?) echo match; esac: equivalente POSIX
    • [[ ab =~ 'ab?' ]]: Falso4, perde la magia con ''
    • [[ ab? =~ 'ab?' ]]: Vero
  • =~

    • [[ ab =~ ab? ]]: Vero, POSIX espressione regolare estesa corrispondenza, ? 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 riga singola)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': equivalente POSIX.

Raccomandazione : utilizzare sempre [].

Esistono equivalenti POSIX per ogni costrutto [[ ]] Che ho visto.

Se usi [[ ]] Tu:

  • perdere la portabilità
  • costringere il lettore a imparare le complessità di un'altra estensione bash. [ È solo un comando regolare con un nome strano, non è richiesta alcuna semantica speciale.

¹ Ispirato al costrutto equivalente [[...]] In Korn Shell

² ma non riesce per alcuni valori di a o b (come + O index) e esegue un confronto numerico se a e b sembrano numeri interi decimali. expr "x$a" '<' "x$b" Funziona attorno 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 sebbene il raggruppamento (qui con il gruppo di comandi {...;} invece di (...) che eseguirà una subshell non necessaria) non è necessario poiché gli operatori Shell || e && (al contrario degli operatori || e &&[[...]] o gli operatori -o/-a[ hanno uguale precedenza. Quindi [ a = a ] || [ a = b ] && [ a = b ] Sarebbe equivalente.

Single Bracket vale a dire [] è conforme alla shell POSIX per racchiudere un'espressione condizionale.

doppie parentesi ovvero [[]] è una versione migliorata (o estensione) della versione POSIX standard, supportata da bash e altre shell (zsh, ksh).

In bash, per il confronto numerico usiamo eq, ne, lt e gt, con parentesi doppie per il confronto possiamo usare ==, !=, <, e > letteralmente.

  • [ è sinonimo di comando test. Anche se è integrato in 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
6
Premraj

Sulla base di una lettura veloce delle sezioni pertinenti della pagina man, la differenza principale sembra essere che il == e != operatori corrispondono a un modello, piuttosto che a una stringa letterale, e anche che c'è il =~ operatore di confronto regex.

4
womble