Как использовать переменные в цикле bash for

Как использовать переменную в цикле bash for? Если я просто использую стандарт для цикла, он делает то, что я ожидаю

for i in {0..3}
do
   echo "do some stuff $i"
done

Это прекрасно работает. Он проходит через 4 раза, от 0 до 3 включительно, печатает мое сообщение и помещает счет в конце.

do some stuff 0
do some stuff 1
do some stuff 2
do some stuff 3

Когда я пытаюсь сделать то же самое со следующим для цикла, это похоже на строку, которая не то, что я хочу.

length=3
for i in {0..$length}
do
   echo "do something right $i"
done

выход:

do something right {0..3}

Я пробовал

for i in {0.."$length"} and for i in {0..${length}} (both output was {0..3})

и

for i in {0..'$length'} (output was {0..$length})

и они оба не делают то, что мне нужно. Надеюсь, кто-то может мне помочь. Заранее благодарим за любую bash экспертную помощь для циклов.

Ответ 1

Один из способов: eval:

for i in $( eval echo {0..$length} )
do
       echo "do something right $i"
done

Обратите внимание, что происходит, если вы устанавливаете length=;ls или length=; rm * (не пытайтесь использовать последний).

безопасно, используя seq:

for i in $( seq 0 $length )
do
       echo "do something right $i"
done

или вы можете использовать цикл c-style for, который также безопасен:

for (( i = 0; i <= $length; i++ )) 
do 
       echo "do something right $i"
done

Ответ 2

В bash, расширение скобки является первым шагом, предпринятым таким образом, в этот момент $length не будет заменен.

В manpage для bash четко указано:

Выражение последовательности принимает вид {x..y [.. incr]}, где x и y либо целые числа, либо одиночные символы...

Существует несколько возможностей, таких как использование:

pax> for i in $(seq 0 $length) ; do echo $i ; done
0
1
2
3

хотя это может дать вам большую командную строку, если length массивный.

Другой альтернативой является использование синтаксиса C-like:

pax> for (( i = 0; i <= $length; i++ )) ; do echo $i; done
0
1
2
3

Ответ 3

Субтитры брейков выполняются перед любыми другими, поэтому вам нужно использовать eval или сторонний инструмент, например seq.

Пример для eval:

for i in `eval echo {0..$length}`; do echo $i; done

Эта информация действительно может быть найдена в man bash:

Выражение последовательности принимает вид {x..y [.. incr]}, , где x и y являются либо  целые числа или одиночные символы, а incr - необязательный приращение - целое число.  [...]

Расширение скобки выполняется перед любыми другими расширениями, а любые специальные символы  к другим расширениям сохраняются в результате. Это строго текстовое.   Bash не применяет синтаксической интерпретации к контексту расширения  или текст между фигурными скобками.