Jak mogę użyć zmiennej $ w rozszerzeniu nawiasu klamrowego sekwencji?


33

Chcę użyć $var inrozszerzenia nawiasów klamrowych z zakresem, w bash. Po prostu stawianie {$var1..$var2}nie działa, więc poszedłem „bocznie” ...

Poniższe działa, ale jest trochę kludgey.

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

Czy istnieje bardziej „normalny” sposób?

Odpowiedzi:


26

Możesz spróbować:

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

Nie jestem pewien, czy to najlepsza odpowiedź, ale na pewno jest jedna.


Durrh! :( Nie widziałem oczywistego ... Dzięki :)
Peter.O

4
W bash, ekspansja {} występuje przed $ ekspansją, więc nie sądzę, że istnieje inny sposób, niż użycie eval lub innej sztuczki, aby spowodować dwa przejścia przez wyrażenie.
mattdm

6
Właśnie „dostał” to! ... Nie ma żadnego ekspansja klamra z {$one..$three}, ponieważ nie jest poprawnym forma Brace-ekspansji, który w tym przypadku oczekuje całkowitymi ... Staje się tylko ważna forma po rozszerzeniu $ var, który evalnastępnie przechodzi przez ten sam proces, aby wygenerować normalne rozwinięcie sekwencji nawiasów ... 1 2 3 QED;) ... Podsumowanie: prosta obecność pary nawiasów klamrowych nie powoduje rozszerzenia nawiasów klamrowych ... wyzwala go tylko poprawna forma .
Peter.O,

@fred: Welcome :-)
asoundmove 21.02.11

Gdy używasz zmiennej takiej jak a={0..9}; echo $a;brak rozszerzenia nawiasów klamrowych . Korzystanie eval, to działa. Myślę więc, że wyjaśnienie @ mattdm jest dobre.
dr0i

20

Jak już sobie sprawę, {1..3}rozszerza się 1 2 3, ale {foo..bar}czy {$foo..$bar}nie wyzwalają rozwijanie nawiasów, a ten ostatni jest następnie rozszerzony w celu zastąpienia $fooi $barich wartości.

Powrót do GNU (np. Niewbudowany Linux) to seqpolecenie.

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

Inna możliwość. jeśli foo.nie zawiera znaku specjalnego powłoki, to

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

Najprostszym rozwiązaniem jest użycie zsh, gdzie rm foo.{$ext0..$extN}robi to, co chcesz.


Dzięki za opcje. Dobrze jest je wszystkie pogrupować. Będę trzymał się bashu i eval ... eval jest teraz wystarczająco prosty, kiedy wiem, co się dzieje za kulisami; więc to już nie problem. Nie trzeba zmieniać dobrego konia z powodu jeźdźca
:)

1

Podczas gdy inne odpowiedzi omawiają użycie evali seq, bashmożesz użyć tradycyjnej forpętli w stylu C w kontekście arytmetycznym. Zmienne ext0i extNsą rozwinięte wewnątrz, ((..))powodując uruchomienie pętli dla zdefiniowanego zakresu.

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

Jeśli szukasz optymalnego sposobu i unikniesz wielu rmpoleceń, możesz użyć tymczasowego symbolu zastępczego, aby zapisać wyniki nazwy pliku i zadzwonić rmza jednym razem.

 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

i teraz wywołaj rmpolecenie w rozszerzonej tablicy

 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

Uwagi:

  • Korzystanie z eval naraża na ryzyko związane z iniekcją poleceń
  • Linux wypisze „00 \ n01 \ n02..etc”, ale OSX wypisze „1 \ n2 \ n ... itd.”
  • Użycie sekwencji lub stylu C dla pętli nie będzie pasowało do obsługi wiodących zer przez rozwinięcie nawiasów
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.