Come usare parentesi doppie o singole, parentesi, parentesi graffe


658

Sono confuso dall'uso di parentesi, parentesi, parentesi graffe in Bash, nonché dalla differenza tra le loro forme doppie o singole. C'è una spiegazione chiara?

Risposte:


606

In Bash, teste [sono integrati nella shell.

La parentesi doppia , che è una parola chiave shell, consente funzionalità aggiuntive. Ad esempio, è possibile utilizzare &&e ||invece di -ae -oe c'è un regolare operatore di espressione di corrispondenza =~.

Inoltre, in un semplice test, le parentesi quadre doppie sembrano valutare molto più velocemente di quelle singole.

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done

real    0m24.548s
user    0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done

real    0m33.478s
user    0m33.478s
sys 0m0.000s

Le parentesi graffe, oltre a delimitare un nome di variabile, vengono utilizzate per l' espansione dei parametri in modo da poter fare cose come:

  • Tronca il contenuto di una variabile

    $ var="abcde"; echo ${var%d*}
    abc
    
  • Rendi le sostituzioni simili a sed

    $ var="abcde"; echo ${var/de/12}
    abc12
    
  • Usa un valore predefinito

    $ default="hello"; unset var; echo ${var:-$default}
    hello
    
  • e molti altri ancora

Inoltre, le espansioni di controvento creano elenchi di stringhe che sono in genere ripetute nei loop:

$ echo f{oo,ee,a}d
food feed fad

$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")

$ for num in {000..2}; do echo "$num"; done
000
001
002

$ echo {00..8..2}
00 02 04 06 08

$ echo {D..T..4}
D H L P T

Si noti che le funzioni di zero e incremento iniziali non erano disponibili prima di Bash 4.

Grazie a gboffi per avermi ricordato le espansioni del tutore.

Le doppie parentesi vengono utilizzate per le operazioni aritmetiche :

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

e consentono di omettere i segni del dollaro sulle variabili intere e array e includere spazi attorno agli operatori per la leggibilità.

Le parentesi singole vengono utilizzate anche per gli indici di array :

array[4]="hello"

element=${array[index]}

Sono richiesti parentesi graffe per (quasi / tutti?) I riferimenti di matrice sul lato destro.

Il commento di ephemient mi ha ricordato che le parentesi sono usate anche per i subshells. E che sono usati per creare array.

array=(1 2 3)
echo ${array[1]}
2

8
ATTENZIONE: quella funzione è una bomba a forcella, non eseguirla. Vedi: en.wikipedia.org/wiki/Fork_bomb
In pausa fino a nuovo avviso.

3
È solo una bomba se la invochi con un'ulteriore :.
effimero

7
Anche per completezza, l'ho appena trovato in una vecchia sceneggiatura $[expression]:; questa è la sintassi dell'espressione aritmetica obsoleta e deprecata per la sintassi più nuova e preferita:$((expression))
michael,

2
@DennisWilliamson Un altro uso di parentesi graffe bashè la creazione di sequenze, come indicato di seguito sotto ( stackoverflow.com/a/8552128/2749397 ). Mi sto prendendo la libertà di usare la risposta più votata come veicolo ... Due esempi di letterali di sequenza: echo {01..12}-> 01 02 03 04 05 06 07 08 09 10 11 12(nota lo zero iniziale); echo {C..Q}-> C D E F G H I J K L M N O P Q. Il suo uso principale è nei loop, ad es. for cnt in {01..12} ; do ... ${cnt} ... ; done
gboffi

1
@gboffi: la funzione di riempimento zero è diventata disponibile in Bash 4. Inoltre, in Bash 4, è possibile specificare un incremento in una sequenza: echo {01..12..2}-> "01 03 05 07 09 11". Grazie per il promemoria sulle sequenze. Lo aggiungerò alla mia risposta.
In pausa fino a nuovo avviso.

336
  1. Una singola parentesi ( [) di solito in realtà chiama un programma chiamato [; man testo man [per maggiori informazioni. Esempio:

    $ VARIABLE=abcdef
    $ if [ $VARIABLE == abcdef ] ; then echo yes ; else echo no ; fi
    yes
    
  2. La doppia parentesi ( [[) fa la stessa cosa (fondamentalmente) di una singola parentesi, ma è un built-in bash.

    $ VARIABLE=abcdef
    $ if [[ $VARIABLE == 123456 ]] ; then echo yes ; else echo no ; fi
    no
    
  3. Le parentesi ( ()) vengono utilizzate per creare una subshell. Per esempio:

    $ pwd
    /home/user 
    $ (cd /tmp; pwd)
    /tmp
    $ pwd
    /home/user
    

    Come puoi vedere, la subshell ti ha permesso di eseguire operazioni senza influire sull'ambiente della shell corrente.

  4. (a) Le parentesi graffe ( {}) vengono utilizzate per identificare in modo univoco le variabili. Esempio:

    $ VARIABLE=abcdef
    $ echo Variable: $VARIABLE
    Variable: abcdef
    $ echo Variable: $VARIABLE123456
    Variable:
    $ echo Variable: ${VARIABLE}123456
    Variable: abcdef123456
    

    (b) Le parentesi graffe vengono anche utilizzate per eseguire una sequenza di comandi nel contesto della shell corrente , ad es

    $ { date; top -b -n1 | head ; } >logfile 
    # 'date' and 'top' output are concatenated, 
    # could be useful sometimes to hunt for a top loader )
    
    $ { date; make 2>&1; date; } | tee logfile
    # now we can calculate the duration of a build from the logfile
    

Vi è tuttavia una sottile differenza sintattica ( )(vedi riferimento bash ); essenzialmente, una virgola ;dopo l'ultimo comando tra parentesi graffe è un must, e le bretelle {, } deve essere circondato da spazi.


26
Bene, in [realtà è un builtin in Bash, ma dovrebbe agire come /bin/[al contrario del [[builtin. [[ha caratteristiche diverse, come più operazioni logiche e ruoli di quotazione diversi. Inoltre: le parentesi singole vengono utilizzate anche per array, sostituzione di processo e globi estesi; le doppie parentesi sono usate per l'aritmetica; le parentesi graffe {}vengono utilizzate per il raggruppamento dei comandi o una moltitudine di tipi di espansione dei parametri o espansione delle parentesi graffe o espansione della sequenza. Sono sicuro di aver perso anche altri usi ...
effimero

4
Il doppio uguale nell'espressione if [ $VARIABLE == abcdef ]è un basismo che, sebbene funzioni, dovrebbe probabilmente essere evitato; utilizzare esplicitamente bash ( if [[ ...==...]]) o chiarire che si sta utilizzando il condizionale più tradizionale ( if [ "$VARIABLE" = "abcdef" ]). Probabilmente, gli script dovrebbero iniziare nel modo più semplice e portatile possibile, fino a quando non hanno davvero bisogno di funzionalità specifiche per bash (per una ragione o per l'altra). Ma in ogni caso, l'intento dovrebbe essere chiaro; "=" e "==" e "[[" e "[" funzionano in modo diverso e il loro utilizzo deve essere coerente.
michael,

3
@michael_n: +1 per questa osservazione. A proposito, adoro lo scripting, ma trovo abbastanza imbarazzante che il modo portatile sia testare tramite [ "$var" = ".."]invece di ==, mentre in C assegnerebbe invece di test (ed è una causa abbastanza comune di bug) ... perché 't testutilizzare ==al posto di =? qualcuno lo sa?
Olivier Dulac,

Inoltre ecco una cosa divertente che (almeno su Kubuntu) il comando /usr/bin/[non è un link simbolico a /usr/bin/test, e altro ancora: questi programmi hanno anche dimensioni diverse!
Hi-Angel,

Inoltre: una singola parentesi di chiusura )fa parte della casesintassi dell'istruzione per terminare una riga del caso. Non ha una parentesi aperta. Questo mi ha gettato via la prima volta che l'ho visto.
Agustín Amenabar,

302

Parentesi

if [ CONDITION ]    Test construct  
if [[ CONDITION ]]  Extended test construct  
Array[1]=element1   Array initialization  
[a-z]               Range of characters within a Regular Expression
$[ expression ]     A non-standard & obsolete version of $(( expression )) [1]

[1] http://wiki.bash-hackers.org/scripting/obsolete

Parentesi graffe

${variable}                             Parameter substitution  
${!variable}                            Indirect variable reference  
{ command1; command2; . . . commandN; } Block of code  
{string1,string2,string3,...}           Brace expansion  
{a..z}                                  Extended brace expansion  
{}                                      Text replacement, after find and xargs

parentesi

( command1; command2 )             Command group executed within a subshell  
Array=(element1 element2 element3) Array initialization  
result=$(COMMAND)                  Command substitution, new style  
>(COMMAND)                         Process substitution  
<(COMMAND)                         Process substitution 

Parentesi doppie

(( var = 78 ))            Integer arithmetic   
var=$(( 20 + 5 ))         Integer arithmetic, with variable assignment   
(( var++ ))               C-style variable increment   
(( var-- ))               C-style variable decrement   
(( var0 = var1<98?9:21 )) C-style ternary operation

@Yola, potresti spiegare cosa significa esattamente $ (varname)? Nei progetti Apple Xcode, posso specificare i percorsi dei file come input / output dello script. se specifico $ SRC_ROOT / myFile.txt o $ {SRC_ROOT} /myFile.txt (SRC_ROOT var viene esportato dal sistema di generazione) - non funziona. funziona solo $ (SRC_ROOT) /myFile.txt. Quale potrebbe essere la ragione? chiaramente var name non è un comando?
Motti Shneor,

1
@MottiShneor, nel tuo caso $(varname)non è correlato alla sintassi bash. Fa parte della sintassi di Makefile .
Sasha,

Non è così - Xcode non sta costruendo usando i makefile e le sue variabili sono variabili d'ambiente. I processi proprietari del sistema di build Xcode leggono i valori di queste variabili d'ambiente predefinite. I passaggi personalizzati sono solo normali script di shell (bash o altro) e hanno accesso agli stessi parametri.
Motti Shneor,

@MottiShneor, ok, perfezioniamo: molto probabilmente fa parte della sintassi di xcconfig . Comunque, $(varname)non ha alcuna relazione con la sintassi bash nel tuo caso.
Sasha,

Non menzioni la differenza tra il costrutto di test e il costrutto di test esteso.
Nikos,

23

Volevo solo aggiungere questi da TLDP :

~:$ echo $SHELL
/bin/bash

~:$ echo ${#SHELL}
9

~:$ ARRAY=(one two three)

~:$ echo ${#ARRAY}
3

~:$ echo ${TEST:-test}
test

~:$ echo $TEST


~:$ export TEST=a_string

~:$ echo ${TEST:-test}
a_string

~:$ echo ${TEST2:-$TEST}
a_string

~:$ echo $TEST2


~:$ echo ${TEST2:=$TEST}
a_string

~:$ echo $TEST2
a_string

~:$ export STRING="thisisaverylongname"

~:$ echo ${STRING:4}
isaverylongname

~:$ echo ${STRING:6:5}
avery

~:$ echo ${ARRAY[*]}
one two one three one four

~:$ echo ${ARRAY[*]#one}
two three four

~:$ echo ${ARRAY[*]#t}
one wo one hree one four

~:$ echo ${ARRAY[*]#t*}
one wo one hree one four

~:$ echo ${ARRAY[*]##t*}
one one one four

~:$ echo $STRING
thisisaverylongname

~:$ echo ${STRING%name}
thisisaverylong

~:$ echo ${STRING/name/string}
thisisaverylongstring

18
Mente che echo ${#ARRAY}mostra tre, a causa del primo elemento del ARRAYcontiene tre caratteri, non perché contiene tre elementi! Per stampare il numero di elementi utilizzare echo ${#ARRAY[@]}.
TrueY

@zeal è ${TEST:-test}uguale $TESTse la variabile TESTesiste, altrimenti restituisce semplicemente la stringa "test". Esiste un'altra versione che fa ancora di più: ${TEST:=test}--- che equivale anche a $TESTse TEST esiste, ma ogni volta che non lo fa, crea la variabile TESTe assegna un valore "test" e diventa anche il valore dell'intera espressione.
Loves Probability,

18

La differenza tra test , [ e [[ è spiegata in dettaglio nel BashFAQ .

Per farla breve: test implementa la vecchia sintassi portatile del comando. In quasi tutte le shell (le più vecchie shell Bourne sono l'eccezione), [è sinonimo di test (ma richiede un argomento finale di]). Sebbene tutte le shell moderne abbiano implementazioni integrate di [, di solito esiste ancora un eseguibile esterno con quel nome, ad esempio / bin / [.

[[ne è una nuova versione migliorata, che è una parola chiave, non un programma. Ciò ha effetti benefici sulla facilità d'uso, come mostrato di seguito. [[è compreso da KornShell e BASH (ad es. 2.03), ma non da POSIX o BourneShell precedenti.

E la conclusione:

Quando dovrebbe essere usato il nuovo comando test [[e quando quello vecchio [? Se la portabilità su BourneShell è un problema, è necessario utilizzare la vecchia sintassi. Se invece lo script richiede BASH o KornShell, la nuova sintassi è molto più flessibile.


18

Parentesi nella definizione della funzione

Le parentesi ()vengono utilizzate nella definizione della funzione:

function_name () { command1 ; command2 ; }

Questo è il motivo per cui devi sfuggire alle parentesi anche nei parametri di comando:

$ echo (
bash: syntax error near unexpected token `newline'

$ echo \(
(

$ echo () { command echo The command echo was redefined. ; }
$ echo anything
The command echo was redefined.

Oh, ho provato con il csh. Colpa mia. Quando provo su bash, funziona. Non conoscevo il comando 'comando' di bash.
Chan Kim,

come posso annullare la ridefinizione del comando echo ()? (senza riaprire la bash)
Chan Kim

2
@ChanKim: unset -f echo. Vedere help unset.
pabouk,

0
Truncate the contents of a variable

$ var="abcde"; echo ${var%d*}
abc

Make substitutions similar to sed

$ var="abcde"; echo ${var/de/12}
abc12

Use a default value

$ default="hello"; unset var; echo ${var:-$default}
hello

Quando rispondi a una domanda, non mirare solo al "codice", ma prova anche ad aggiungere una spiegazione ...
Mikev,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.