Quando {a, b, c} viene espanso in bash, quando non lo è?


13

Uno script bash che contiene

for i in {a,b}-{1,2}; do
  echo $i;
done

stampe

a-1
a-2
b-1
b-2

quando eseguito. Questo è quello che mi aspettavo, con l' {a,b}espansione del costrutto.

Tuttavia, quando (un altro) script contiene

v={a,b}-{1,2}
echo $v

stampa

{a,b}-{1,2}

che non è quello che mi aspettavo. Mi aspettavo che stampasse a-1 a-2 b-1 b-2. Ovviamente, il {a,b}costrutto non è espanso.

Posso farlo espandere così

v=$(echo {a,b}-{1,2})

Sulla base di queste osservazioni ho due domande: 1) quando viene {a,b}espanso il costrutto? 2) è $(echo {a,b}-{1,2})il modo preferito per innescare un'espansione quando richiesto?


1
Ciò è, almeno, coerente con il fatto che non è possibile creare una variabile array con un semplice =. Ad esempio, v=a-1 a-2non funzionerà.
grochmal

@grochmal - questo perché stai assegnando un valore scalare. v=a-1 a-2significa assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)assegna l'array alla variabile v. v+=(b-1 b-2)si aggiunge ad esso.
CAS

Risposte:


15

Il manuale di Bash dice che:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

L'espansione del controvento non è nell'elenco, quindi non viene eseguita per l'assegnazione v={a,b}-{1,2}. Come menzionato da @Wildcard, la semplice espansione v=a-1 v=b-1 ...sarebbe comunque insensata.

Inoltre, quando si esegue il echo $v, si applica quanto segue:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

L'espansione delle parentesi graffe si verifica prima dell'espansione variabile, quindi le parentesi graffe assegnate $vnon vengono espanse.

Ma puoi fare cose come questa:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

L'espansione con $(echo ...)dovrebbe funzionare se non hai spazi bianchi nella stringa da espandere, e quindi non si verificheranno problemi con la suddivisione delle parole. Un modo migliore potrebbe essere quello di utilizzare una variabile array se è possibile.

ad es. salvare l'espansione in un array ed eseguire alcuni comandi con i valori espansi:

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"

5

Un punto interessante Forse utile è il seguente estratto da man bash:

Una variabile può essere assegnata da un'istruzione del modulo

      nome = [ valore ]

Se non viene fornito alcun valore , alla variabile viene assegnata la stringa null. Tutti i valori subiscono espansione tilde, espansione parametri e variabili, sostituzione comandi, espansione aritmetica e rimozione virgolette (vedere ESPANSIONE di seguito).

Si noti che l'espansione del controvento NON è menzionata nell'elenco.

Tuttavia, ciò lascia ancora una domanda, vale a dire: come fa la shell a sapere che si tratta di un'assegnazione variabile e quindi non soggetta all'espansione del controvento? O più precisamente, dove viene chiarita e codificata la sequenza di analisi in modo tale che la shell sia definita per identificare le assegnazioni di variabili prima che gestisca l'espansione del controvento? (Questo è ovviamente come bashfunziona, ma non ho trovato la riga esatta della documentazione che descrive questo.)


1
Forse questo ? "2. Le parole che non sono assegnazioni variabili o reindirizzamenti vengono espanse (vedere Espansioni della shell)."
Jeff Schaller

@JeffSchaller, hai ragione. In realtà a questa domanda si risponde meglio semplicemente leggendo la sezione "SEMPLICE ESPANSIONE DI COMANDI" ( LESS=+/SIMPLE man bash).
Wildcard il

0

secondo la mia piccola conoscenza, {a, b, c} viene espanso quando viene ripetuto direttamente o utilizzato con un comando, ad esempio: mkdir ~ / {a, b, c}, ma quando è impostato su una variabile dovrebbe essere valutato prima riecheggiandolo o usandolo come oggetto!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

poiché hai "a" seguito da "b" in ordine alfa [az] e "1" seguito da "2" in ordine decrescente [0-9]: puoi usare il doppio punto ".." insteed of virgola ", "

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

1
La domanda è: perché vnon è stato impostato sulla stringa letterale "a-1 a-2 b-1 b-2". O almeno perché non si genera alcun errore quando si digita il comando: v=a-1 v=a-2 v=b-1 v=b-2(a cui ci si aspetterebbe di espandere l'assegnazione di variabile). È una buona domanda; questo non risponde davvero.
Wildcard il

@SatoKatsura, cosa significa "espansione con caratteri jolly"? Esiste l'espansione dei parametri, l'espansione del nome percorso e l'espansione del controvento, a cui potresti fare riferimento e che sono tutti diversi. Oppure intendevi spaccare le parole?
Wildcard il

0

L'assegnazione a una variabile in bash non espande l'espressione.

Per questo piccolo script, x conterrà "*"e non l'espansione di "*":

#!/bin/bash
x=*
echo "$x"

Tuttavia, alcuni valori vengono espansi, rif. la bella risposta di ilkkachu.

Le espressioni vengono espanse quando vengono valutate.

Come questo:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

O così:

x=*
echo $x            # <-- evaluation of $x

O così:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

Il trigger $()è abbastanza comune e penso che sia preferito rispetto al passato eval, ma probabilmente il migliore è non attivare affatto la valutazione, fino a quando la variabile non viene effettivamente utilizzata in un comando.

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.