Come posso usare $ variabile in un'espansione del controvento di una sequenza?


33

Voglio usare $var inun'espansione di parentesi graffe shell con un intervallo, in bash. Mettere semplicemente {$var1..$var2}non funziona, quindi sono andato "lateralmente" ...

Il seguente funziona, ma è un po 'kludgey.

# remove the split files
echo rm foo.{$ext0..$extN} rm-segments > rm-segments
source rm-segments

C'è un modo più "normale"?

Risposte:


26

Puoi provare:

eval rm foo.{$ext0..$extN}

Non sono sicuro che questa sia la risposta migliore, ma sicuramente è una.


Durrh! :( Non riuscivo a vedere l'ovvio ... Grazie :)
Peter.O

4
In bash, l'espansione {} avviene prima dell'espansione $, quindi non credo che ci sia altro modo per farlo se non usare eval o qualche altro trucco per causare due passaggi nell'espressione.
Mattdm,

6
Ho appena "preso" è! ... Non v'è alcuna espansione delle parentesi graffe con {$one..$three}, perché non è una valida forma di brace-espansione, che in questo caso si aspetta che i numeri interi ... Si diventa solo una valida forma dopo l'espansione $ var, che evalpassa quindi attraverso lo stesso processo per generare una normale espansione della sequenza di parentesi graffe ... 1 2 3 QED;) ... Riepilogo: la semplice presenza di una coppia di parentesi graffe non attiva l'espansione di parentesi graffe ... solo una forma valida la attiva .
Peter

@fred: Benvenuto :-)
asoundmove,

Quando si utilizza una variabile come a={0..9}; echo $a;non esiste un'estensione di parentesi graffa . Usando eval, funziona. Quindi penso che la spiegazione di @ mattdm sia buona.
dr0i,

20

Come già realizzato, {1..3}si espande a 1 2 3ma {foo..bar}o {$foo..$bar}non attivano espansione delle parentesi graffe, e quest'ultimo viene successivamente ampliato per sostituire $fooe $bardai loro valori.

Un fallback su GNU (ad es. Linux non incorporato) è il seqcomando.

for x in `seq $ext0 $extN`; do rm foo.$x; done

Un'altra possibilità. se foo.non contiene caratteri speciali shell, è

rm `seq $ext0 $extN | sed 's/^/foo./'`

La soluzione più semplice è usare zsh, dove rm foo.{$ext0..$extN}fa quello che vuoi.


Grazie per le opzioni .. È bello vederli tutti raggruppati .. Continuerò con bash ed eval ... eval è abbastanza semplice ora che so cosa sta succedendo dietro le quinte; quindi non è più un problema. Non c'è bisogno di cambiare un buon cavallo a causa del cavaliere
:)

1

Mentre le altre risposte discutono di usare evale seq, in bash, puoi usare un tradizionale forciclo in stile C in un contesto aritmetico. Le variabili ext0e extNvengono espanse all'interno ((..))causando l'esecuzione del ciclo per l'intervallo definito.

for (( idx = ext0; idx <= extN; idx++ )); do
    [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
    rm "$foo.$idx"
done

Se stai cercando un modo ottimale ed eviti più rmcomandi, puoi utilizzare un segnaposto temporaneo per memorizzare i risultati del nome file e chiamare rmin un colpo solo.

 results=()
 for (( idx = ext0; idx <= extN; idx++ )); do
     [[ -f "$foo.$idx" ]] || { printf "file %s does not exist" "$foo.$idx" >&2 ; continue }
     results+=( "$foo.$idx" )
 done

e ora chiama il rmcomando sull'array espanso

 rm -- "${results[@]}"

0
    function f_over_range {
        for i in $(eval echo {$1..$2}); do
            f $i
        done
    }

    function f {
        echo $1
    }

    f_over_range 0 5
    f_over_range 00 05

Gli appunti:

  • L'uso di eval espone il rischio di sicurezza nell'iniezione di comandi
  • Linux stamperà "00 \ n01 \ n02..etc", ma OSX stamperà "1 \ n2 \ n ... ecc"
  • L'uso di seq o C-style per i loop non corrisponderà alla gestione dell'espansione degli zeri iniziali
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.