Як я можу використовувати змінну $ у розширенні послідовності дужок оболонки?


33

Я хочу використовувати $var inрозширення підтяжки оболонки з діапазоном, в bash. Простіше кажучи {$var1..$var2}, не працює, тому я пішов "бічно" ...

Наступні роботи, але це трохи дивовижно.

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

Чи є більш "нормальний" спосіб?

Відповіді:


26

Ви можете спробувати:

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

Не впевнений, це найкраща відповідь, але це, безумовно, одна.


Дурр! :( Я не міг бачити очевидного ... Спасибі :)
Peter.O

4
У bash, {} розширення відбувається перед $ розширенням, тому я не думаю, що існує інший спосіб зробити це, крім використання eval або якогось іншого трюку, щоб викликати два проходи через вираз.
mattdm

6
Я просто "отримав" це! ... Немає розширення дужки з {$one..$three}, оскільки це не є дійсною формою розширення дужок, яка в цьому випадку очікує цілих чисел ... Вона стає дійсною формою лише після розширення $ var, який evalпотім проходить через той самий процес, щоб генерувати нормальне розширення послідовності дужок ... 1 2 3 QED;) ... Підсумок: проста присутність брекет-пари не запускає розширення дужки ... тільки правильна форма запускає це .
Пітер.O

@fred: Ласкаво просимо :-)
asoundmove

При використанні змінної на зразок a={0..9}; echo $a;відсутнє розширення дужок . Використовуючи eval, це працює. Тому я думаю, що пояснення @ mattdm добре.
dr0i

20

Як ви вже зрозуміли, {1..3}розширюється , 1 2 3але {foo..bar}і {$foo..$bar}робити не в фігурних дужках тригера, а останній згодом розширено , щоб замінити $fooі $barїх значеннями.

Команда є резервною копією для GNU (наприклад, невбудований Linux) seq.

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

Інша можливість. якщо foo.не містить спеціального символу оболонки, є

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

Найпростіше рішення - використовувати zsh, де rm foo.{$ext0..$extN}робити те, що хочеш.


Дякую за варіанти .. Добре бачити їх усі згруповані .. Я буду дотримуватися bash та eval ... eval досить простий зараз, коли я знаю, що відбувається за лаштунками; тому це вже не проблема. Не потрібно міняти хорошого коня через вершника:) ...
Пітер.O

1

Хоча в інших відповідях обговорюється використання evalта seq, в bash, ви можете використовувати традиційний forцикл стилю С в арифметичному контексті. Змінні ext0та extNрозгорнуті всередині ((..))викликає цикл для визначеного діапазону.

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

Якщо ви шукаєте оптимальний спосіб і уникаєте декількох rmкоманд, ви можете використовувати тимчасовий заповнювач для зберігання результатів імені файлів та виклику rmв один кадр.

 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

і тепер викликайте rmкоманду на розширеному масиві

 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

Примітки:

  • Використання eval наражає на небезпеку безпеку введення команди
  • Linux надрукує "00 \ n01 \ n02..etc", але OSX надрукує "1 \ n2 \ n ... тощо"
  • Використання seq або C-стилів для циклів не збігається з керуванням розширенням дужок із провідними нулями
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.