È doppie parentesi quadre [[ ]] preferibile rispetto all’unica parentesi quadre [ ] in Bash?

Un co-lavoratore affermato di recente in una revisione del codice che il [[ ]] costruire deve essere preferito a [ ] in costrutti come

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

Non riusciva a fornire una spiegazione logica. C’è qualcuno?

  • Essere flessibili, a volte permettete a voi stessi di ascoltare un consiglio senza la necessità di una sua profonda spiegazione 🙂 Come per [[ con esso il codice è valido e chiaro, ma il ricordo di quel giorno, quando ti porta il tuo scriptworks sul sistema con la shell di default che non è bash o ksh, etc. [ è più brutto, scomodo, ma funziona come AK-47 in qualsiasi situazione.
  • È possibile ascoltare un consiglio, senza una profonda spiegazione, certo. Ma quando è richiesta una spiegazione e non la ottiene, è generalmente una bandiera rossa. “La fiducia, ma verificare” e tutti che.
  • Vedi anche: Qual è la differenza tra il Bash operatori [[ vs [ vs ( vs ((? Unix & Linux SE.
InformationsquelleAutor Leonard | 2009-03-21

 

8 Replies
  1. 530

    [[ ha meno di sorprese ed è generalmente sicuro da usare. Ma non è portatile – POSIX non specifica che cosa fa e solo alcuni gusci di supporto (accanto bash, ho sentito ksh supporta anch’esso). Per esempio, si può fare

    [[ -e $b ]]

    per verificare se un file esiste. Ma con [, è da citare la $b, perché divide l’argomento e si espande cose come "a*" (dove [[ prende letteralmente). Che ha anche a che fare con quanto [ può essere un programma esterno e riceve il suo argomento solo normalmente come ogni altro programma (anche se può anche essere un builtin, ma poi ancora non ha questa gestione speciale).

    [[ ha anche alcune altre caratteristiche interessanti, come espressioni regolari con =~ insieme con gli operatori, come sono conosciuti in C-come le lingue. Qui è una buona pagina di: Qual è la differenza tra test, [ e [[ ? e Bash Test

    • Considerando che bash è ovunque in questi giorni, io tendo a pensare che è dannatamente portatile. L’unica eccezione comuni per me è busybox piattaforme – ma si sarebbe probabilmente desidera fare uno sforzo speciale per esso in ogni caso, dato l’hardware che funziona.
    • Infatti. Suggerisco che la tua seconda frase smentisce la tua prima; se si considera lo sviluppo di software nel suo complesso”, bash è ovunque” e “l’eccezione è busybox piattaforme” sono completamente incompatibili. busybox è diffuso per lo sviluppo embedded.
    • Anche se bash è installato sul mio box, potrebbe non essere in esecuzione lo script (avrei potuto /bin/sh collegamento simbolico a qualche dash-variante, è di serie su FreeBSD e Ubuntu). Rimane la stranezza con Busybox, che con la standard le opzioni di compilazione, al giorno d’oggi, analizza [[ ]] ma si interpreta nel senso che la stessa [ ].
    • Se si utilizza bash-solo costrutti (come questo), si dovrebbe avere #!/bin/bash, non #!/bin/sh.
    • Che è il motivo per cui faccio il mio script #!/bin/sh per poi passare loro di utilizzare #!/bin/bash appena posso contare su alcuni BASH caratteristica specifica, per indicare che non è più Bourne shell portatile.
    • bash è disponibile nei porti, ma non è installato di default, su FreeBSD. Simili a solaris ultima volta che ho controllato, ma che è stato un bel po ‘ di tempo fa. Probabilmente AIX troppo. Certo, molto più piccolo di basi installate di distribuzioni Linux, ma sono reali e là fuori.
    • Bash è quasi ovunque, ma in molte situazioni (come quelle accidenti crons) non di default ad esso. Io fare solo importante essere a conoscenza di esso. Non avrei mai provato ad usare [[ ]] nel mio cron se avessi fatto 🙂
    • Si noti che se si installa bash su FreeBSD, non sarà /bin/bash. Sarà /usr/local/bin/bash. Il modo giusto di chiamare un non-standard come interprete bash è #!/usr/bin/env bash.
    • “Ma con [devi citare $b” Per me, sarebbe veramente d’aiuto se si hanno mostrato come citare. Se $b valutati per a*, vuoi solo per citare questo: "$b"?

  2. 82

    Differenze di comportamento

    Alcune differenze su Bash 4.3.11:

    • POSIX vs Bash estensione:

    • regolari comando vs magia

      • [ è solo un normale comando con un nome strano.

        ] è solo un argomento di [ che impedisce ulteriori argomenti da essere utilizzato.

        Ubuntu 16.04 in realtà è un file eseguibile che a /usr/bin/[ forniti da coreutils, ma il bash built-in versione ha la precedenza.

        Nulla è modificato nel modo in cui Bash analizza il comando.

        In particolare, < è il reindirizzamento, && e || concatenare più comandi, ( ) genera subshells a meno che non sfuggì \, di parola e di espansione avviene come di consueto.

      • [[ X ]] è un singolo costrutto che rende X essere analizzato magicamente. <, &&, || e () sono trattati in modo speciale, e la suddivisione in parole le regole sono diverse.

        Ci sono anche altre differenze, come = e =~.

        In Bashese: [ è un built-in comando, e [[ è una parola chiave: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

    • <

    • && e ||

      • [[ a = a && b = b ]]: vero, logico e
      • [ a = a && b = b ]: errore di sintassi, && analizzato come E separatore di comandi cmd1 && cmd2
      • [ a = a -a b = b ]: equivalente, ma sconsigliato da POSIX3
      • [ a = a ] && [ b = b ]: POSIX e affidabile equivalente
    • (

      • [[ (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 equivalent⁵
    • la suddivisione in parole e il nome del file generazione su espansioni (split+glob)

      • x='a b'; [[ $x = 'a b' ]]: vero, le virgolette non sono necessarie
      • x='a b'; [ $x = 'a b' ]: errore di sintassi, si espande per [ 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' ]: POSIX equivalente
    • =

      • [[ ab = a? ]]: vero, perché non il pattern matching (* ? [ sono magici). Non glob espandere i file nella directory corrente.
      • [ ab = a? ]: a? glob si espande. Così può essere true o false a seconda dei file nella directory corrente.
      • [ ab = a\? ]: false, non glob espansione
      • = e == sono le stesse in entrambi i [ e [[, ma == è un Bash estensione.
      • case ab in (a?) echo match; esac: POSIX equivalente
      • [[ ab =~ 'ab?' ]]: false⁴, perde la magia con ''
      • [[ ab? =~ 'ab?' ]]: vero
    • =~

      • [[ ab =~ ab? ]]: true, POSIX espressione regolare estesa partita, ? non glob espandere
      • [ a =~ a ]: errore di sintassi. Senza bash equivalente.
      • printf 'ab\n' | grep -Eq 'ab?': POSIX equivalente (singola linea solo dati)
      • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX equivalente.

    Raccomandazione: utilizzare sempre [].

    Ci sono POSIX equivalenti per ogni [[ ]] costruire ho visto.

    Se si utilizza [[ ]] è:

    • perdere la portabilità
    • forza il lettore a imparare le complessità di un altro bash estensione. [ è solo un normale comando con un nome strano, non semantica sono coinvolti.

    1 Ispirato dall’equivalente [[...]] costruire in Korn shell

    2, ma non per alcuni valori di a o b (come + o index) e fa il confronto numerico se a e b aspetto decimali, numeri interi. expr "x$a" '<' "x$b" opere in giro per entrambi.

    3 e non riesce anche per alcuni valori di a o b come ! o (.

    ⁴ in bash 3.2 e sopra e la compatibilità con bash 3.1 non è abilitato (come con BASH_COMPAT=3.1)

    ⁵ se il raggruppamento (qui {...;} gruppo di comando invece di (...) che sarebbe un inutile subshell) non è necessaria in quanto il || e && operatori di shell (al contrario di || e && [[...]] operatori o il -o/-a [ operatori) hanno la stessa precedenza. Così [ a = a ] || [ a = b ] && [ a = b ] sarebbe equivalente.

    • Buone spiegazioni. Io uso [ per le stesse ragioni.
    • In Bashese 🙂 ha. Bello il chiarimento delle distinzioni e motivo di attaccare con POSIX.
  3. 54

    [[ ]] ha più caratteristiche vi consiglio di dare un’occhiata al Advanced Bash Scripting Guide per ulteriori informazioni, in particolare il extended test di comando sezione Capitolo 7. Test.

    Per inciso, come la guida di note, [[ ]] è stato introdotto nel ksh88 (1988 versione dei Korn shell).

    • Questo è lontano da una bashism, fu introdotta in Korn shell.
    • l’ABS è in realtà considerato un molto poveri di riferimento in molti ambienti, mentre si dispone di una grande quantità di informazioni precise, si tende a prendere molto poco per evitare una vetrina per le cattive pratiche nei suoi esempi, e ha speso una grande quantità della sua vita non è più sviluppato.
    • grazie per il tuo commento, è in grado di essere una buona alternativa. Io non sono un esperto in shell scripting, sto cercando una guida che posso consultare per la scrittura di una sceneggiatura, circa una volta ogni anno e mezzo.
    • il Wooledge BashFAQ e associati wiki sono quello che io uso; sono gestiti attivamente con gli abitanti di Freenode #bash canale (che, anche se a volte pungente, tendono a cura profondamente sulla correttezza). BashFAQ #31, mywiki.wooledge.org/BashFAQ/031, è la pagina direttamente pertinenti a questa domanda.
  4. 9

    Da Quale termine di confronto, di prova, staffa, o doppia staffa, è più veloce? (http://bashcurescancer.com)

    La doppia staffa è un “composto
    comando” dove, come test e il singolo
    staffa sono shell built-in (e in
    realtà sono lo stesso comando). Così,
    la staffa singola e doppia staffa
    eseguire codice diverso.

    Il test e supporto singolo sono il
    la maggior parte dei portatili esistenti come
    separato e comandi esterni.
    Tuttavia, se l’utilizzo di qualsiasi in remoto
    moderna versione di BASH, il doppio
    la staffa è supportato.

    • Che cosa è con l’ossessione di veloce in script di shell? Voglio che portatile e non poteva interessare di meno il miglioramento [[ potrebbe portare. Ma poi, io sono uno della vecchia scuola, vecchio brontolone 🙂
    • Penso che molti gusci di dimostrare builtin versioni di [ e test anche se le versioni esterne esistono anche.
    • in generale sono d’accordo: l’intero scopo di script è (era?) la portabilità (in caso contrario, saremmo codice & compilare, non script)… i due eccezioni posso pensare sono: (1) il completamento della scheda (dove script di completamento possono essere davvero lunghi con un sacco di logica condizionale); e (2) super-prompt (PS1=...crazy stuff... e/o $PROMPT_COMMAND); per questi, non voglio percettibile ritardo nell’esecuzione dello script.
    • Alcuni di ossessione per il più veloce è semplicemente stile. Parità di tutto il resto, perché non incorporano la più efficiente il costrutto di codice nel vostro stile di default, in particolare se il costrutto offre anche più di leggibilità? Quanto riguarda la portabilità, un buon numero di attività che bash è adatto per sono intrinsecamente non-portatile. E. g., Ho bisogno di eseguire apt-get update se è stato più di X ore dall’ultimo. Questo è un grande sollievo quando si può lasciare la portabilità fuori la già troppo lunga lista di vincoli per il codice.
  5. 2

    Una tipica situazione in cui non è possibile utilizzare [[ è un autotools configurare.ac script, c’parentesi ha una speciale e diverso significato, allora si dovrà utilizzare test invece di [ o [[ — Nota che il test e sono lo stesso programma.

    • Dato che gli autotools non sono una shell POSIX, perché sareste mai aspettati [ essere definito come una shell POSIX funzione?
    • Perché il autoconf script sembra uno script di shell, e produce uno script di shell, e la maggior parte dei comandi della shell di operare all’interno di esso.
  6. 1

    Se si sono in seguito Google lo stile di guida:

    Test, [ e [[

    [[ … ]] riduce gli errori di nessun percorso di espansione di parola o di scissione avviene tra [[ e ]] e [[ … ]] consente di regolare l’espressione di corrispondenza in cui [ … ] non.

    # This ensures the string on the left is made up of characters in the
    # alnum character class followed by the string name.
    # Note that the RHS should not be quoted here.
    # For the gory details, see
    # E14 at https://tiswww.case.edu/php/chet/bash/FAQ
    if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
      echo "Match"
    fi
    
    # This matches the exact pattern "f*" (Does not match in this case)
    if [[ "filename" == "f*" ]]; then
      echo "Match"
    fi
    
    # This gives a "too many arguments" error as f* is expanded to the
    # contents of the current directory
    if [ "filename" == f* ]; then
      echo "Match"
    fi
  7. -1

    [[ ]] doppie parentesi quadre sono unsuported in determinate versione di SunOS e totalmente unsuported all’interno della funzione di dichiarazioni :
    GNU bash, versione 2.02.0(1)-release (sparc-sole-solaris2.6)

    • molto vero, e non è affatto irrilevante. bash portabilità su versioni precedenti devono essere considred. La gente dice “bash è onnipresente e portatile, tranne forse per la (inserire esoterico OS qui)” – ma nella mia esperienza, solaris è una di quelle piattaforme in cui è necessario prestare particolare attenzione alla portabilità: non solo di prendere in considerazione vecchie versioni di bash su un sistema operativo più recente, i problemi/bug w/ array, funzioni, ecc;, ma anche le utenze (utilizzato negli script) come tr, sed, awk, tar hanno stranezze & peculiarità su solaris che si dispone di un work-around.
    • si sono così giusto… tanto utilità non POSIX su Solaris, basta guardare il “df” uscita e argomenti… che Vergogna Sole. Speriamo che è scomparendo a poco a poco (tranne in Canada).
    • Solaris 2.6 sul serio? E ‘ stato rilasciato nel 1997 e si è conclusa il supporto nel 2006. Credo che se si sta ancora utilizzando che poi hai altri problemi!. Per inciso è utilizzato Bash v2.02 che è stato colui che ha introdotto la doppia parentesi così dovrebbe funzionare anche su qualcosa di vecchio come che. Solaris 10 dal 2005 usato Bash 3.2.51 e Solaris 11, 2011 utilizza Bash 4.1.11.
    • Re Script portabilità. Su sistemi Linux c’è in genere solo con l’edizione di ogni strumento e che è la GNU edizione. In Solaris in genere hanno una scelta tra un Solaris-nativo edizione o GNU edizione (dire Solaris tar vs GNU tar). Se si dipende da GNU estensioni specifiche, quindi si deve affermare che nel tuo script per essere portatile. Su Solaris farlo anteponendo con la “g”, ad esempio, ` ggrep` se si desidera che la GNU grep.
  8. -2

    In sintesi, [[ è meglio perché non forcella un altro processo. Non ci sono parentesi o una singola staffa è più lenta di una doppia staffa, perché forcelle di un altro processo.

    • Test e sono nomi per lo stesso comando incorporato in bash. Provare a utilizzare type [ di vedere questo.
    • questo è vero, ma [[, in quanto distinta dalla [, sintassi è interpretato da bash interprete della riga di comando. In bash, provare a digitare type [[. unix4linux è corretto che, sebbene classico Bourne shell [ test forcella fuori un nuovo processo per determinare il valore di verità, il [[ sintassi (preso in prestito da ksh da bash, zsh, ecc) non.
    • Io non sono sicuro che la shell Bourne si sta parlando, ma [ è built-in per Bash come Dash (il /bin/sh in tutte derivate da Debian e distribuzioni Linux).
    • Oh, capisco cosa vuoi dire, che è vero. Stavo pensando a qualcosa di simile, ad esempio, /bin/sh su vecchi Solaris, HP/UX sistemi, ma, naturalmente, se avete bisogno di essere compatibili con quelli non si può non utilizza [[ sia.
    • Bourne shell di Bash (un.k.un. Bourne Again SHell).

Lascia un commento