Wie kann ich $ variable in einer Shell-Klammer-Erweiterung einer Sequenz verwenden?


33

Ich möchte $var ineine Shell-Klammer-Erweiterung mit einem Bereich in Bash verwenden. Einfach ausgedrückt {$var1..$var2}funktioniert das nicht, also bin ich "seitlich" gegangen ...

Das Folgende funktioniert, aber es ist ein bisschen klug.

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

Gibt es einen "normaleren" Weg?

Antworten:


26

Vielleicht möchten Sie versuchen:

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

Ich bin nicht sicher, ob dies die beste Antwort ist, aber es ist sicherlich eine.


Durrh! :( Ich konnte das Offensichtliche nicht erkennen ... Danke :)
Peter.O

4
In der Bash findet die {} -Erweiterung vor der $ -Erweiterung statt, daher gibt es meines Erachtens keine andere Möglichkeit, als Eval oder einen anderen Trick zu verwenden, um zwei Durchgänge durch den Ausdruck zu verursachen.
Mattdm

6
Ich habe es gerade "verstanden"! ... Es gibt keine Klammererweiterung mit {$one..$three}, da es keine gültige Form der Klammererweiterung ist, die in diesem Fall Ganzzahlen erwartet ... Es wird erst nach der $ var-Erweiterung eine gültige Form. Dieser evaldurchläuft dann denselben Prozess, um eine normale Klammersequenzerweiterung zu generieren ... 1 2 3 QED;) ... Zusammenfassung: Das einfache Vorhandensein eines Klammerpaars löst keine Klammererweiterung aus ... nur ein gültiges Formular löst dies aus .
Peter.O

@fred: Willkommen :-)
asoundmove

Bei Verwendung einer Variablen wie a={0..9}; echo $a;gibt es keine geschweifte Klammer . Mit eval, es funktioniert. Ich finde die Erklärung von @ mattdm also gut.
dr0i

20

Wie Sie bereits realisiert, {1..3}dehnt sich 1 2 3aber {foo..bar}oder {$foo..$bar}nicht Auslöser Klammer Expansion und diese erweitert wird anschließend zu ersetzen $foound $bardurch ihre Werte.

Ein Fallback auf GNU (zB nicht eingebettetes Linux) ist der seqBefehl.

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

Andere Möglichkeit. Wenn foo.keine Shell Sonderzeichen enthält, ist

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

Die einfachste Lösung ist, zsh zu verwenden, wo rm foo.{$ext0..$extN}Sie tun, was Sie wollen.


Vielen Dank für die Optionen. Es ist gut zu sehen, dass alle gruppiert sind. Ich bleibe bei Bash und Eval. Das ist also kein Problem mehr. Keine Notwendigkeit, ein gutes Pferd wegen des Reiters zu ändern
:)

1

Während die anderen Antworten diskutieren mit evalund seq, in bash, können Sie eine traditionelle C - Stil verwenden forSchleife in einem arithmetischen Kontext. Die Variablen ext0und extNwerden innerhalb ((..))des Bereichs erweitert, in dem die Schleife ausgeführt wird.

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

Wenn Sie einen optimalen Weg suchen und mehrere rmBefehle vermeiden möchten, können Sie einen temporären Platzhalter verwenden, um die Dateinamenergebnisse zu speichern und rmin einem Durchgang aufzurufen .

 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

Rufen Sie nun den rmBefehl im erweiterten Array auf

 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

Anmerkungen:

  • Die Verwendung von eval stellt ein Sicherheitsrisiko für die Befehlsinjektion dar
  • Linux gibt "00 \ n01 \ n02..etc" aus, aber OSX gibt "1 \ n2 \ n ... etc" aus
  • Die Verwendung von seq oder C-style für Schleifen entspricht nicht der Behandlung führender Nullen durch die Klammererweiterung
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.