Bash: для в цикле с расширением скобки в списке

Я хотел бы написать цикл for, в котором возможные значения взяты из другой переменной. Часть, которую я не могу понять, состоит в том, как включить значения, которые требуют расширения скобки. Например:

TEXT="a b c d{a..c} e f"
for VAR in $TEXT; do echo $VAR; done

Что я получаю

a
b
c
d{a..c}
e
f

Но то, что я хочу, это

a
b
c
da
db
dc
e
f

Кто-нибудь знает, как я могу заставить это работать?

Большое спасибо!

3 ответа

Решение

Боюсь, что вам, возможно, придется прибегнуть к eval в этом случае... Однако я бы посоветовал вам избежать использования цикла:

eval "printf '%s\n' $TEXT"

С помощью eval означает, что скобки будут расширены, что приведет к желаемому результату.

Вы можете увидеть, что происходит, используя set -x:

$ set -x
$ eval "printf '%s\n' $TEXT"
+ eval 'printf '\''%s\n'\'' a b c d{a..c} e f'
++ printf '%s\n' a b c da db dc e f
a
b
c
da
db
dc
e
f

Обратите внимание, что расширение происходит до того, как список будет передан в качестве аргументов printf,

Если вы получите, чтобы определить $TEXT и хотите перебрать каждый из его расширенных элементов, я бы предложил вместо этого использовать массив:

text=( a b c d{a..c} e f )
for var in "${text[@]}"; do
    # whatever with "$var"
done

Это предпочтительное решение, так как оно не связано с использованием eval,

РЕДАКТИРОВАТЬ

Пока есть время и место для eval Это не самый безопасный подход для общего случая. См. Почему следует избегать eval в Bash, и что я должен использовать вместо этого? по ряду причин почему.


использование eval:

TEXT="a b c d{a..c} e f"
for VAR in $TEXT; do eval echo $VAR; done

Выход:

a
b
c
da db dc
e
f

Если вы хотите перебрать каждый элемент, вам придется вложить свои циклы:

for VAR in $TEXT; do
  for VAR2 in $(eval echo $VAR); do
    echo $VAR2
  done
done

Выход:

a
b
c
da
db
dc
e
f

Или используйте Eval на TEXT а не каждый элемент:

TEXT="$(eval echo "a b c d{a..c} e f")"
for VAR in $TEXT; do echo $VAR; done

Выход:

a
b
c
da
db
dc
e
f

Без eval, но с подстановкой команд:

$ text="$(echo a b c d{a..c} e f)"
$ echo "$text"
a b c da db dc e f

И, как уже упоминалось в ответе Тома, массив, вероятно, является лучшим способом.

Другие вопросы по тегам