Как я могу использовать переменную $ в расширении оболочки скобки последовательности?


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}

Не уверен, что это лучший ответ, но это, безусловно, один.


Durrh! :( Я не мог видеть очевидное ... Спасибо :)
Peter.O

4
В bash расширение {} происходит до $ extension, поэтому я не думаю, что есть другой способ сделать это, кроме использования eval или другого трюка, чтобы вызвать два прохода через выражение.
Матдм

6
Я просто "получил" это! ... Нет расширения скобки с {$one..$three}, потому что это недопустимая форма расширения скобки, которая в этом случае ожидает целые числа ... Она становится действительной формой только после расширения $ var, который evalзатем проходит через тот же процесс для генерации нормального расширения последовательности фигурных скобок ... 1 2 3 QED;) ... Резюме: простое присутствие пары фигурных скобок не вызывает расширение фигурных скобок ... только действительная форма запускает его ,
Peter.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 достаточно прост, теперь я знаю, что происходит за кулисами; так что это больше не проблема. Не нужно менять хорошего коня из-за наездника
:)

1

В то время как другие ответы обсуждают использование evalи seq, bashвы можете использовать традиционный forцикл в стиле C в арифметическом контексте. Переменные 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-style для циклов не будет соответствовать обработке расширением скобок ведущих нулей
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.