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

65

У меня есть следующий скрипт bash:

#!/bin/bash

upperlim=10

for i in {0..10}
do
echo $i
done

for i in {0..$upperlim}
do
echo $i
done

Первый forцикл ( без переменной upperlimв контроле цикла) работает нормально, а второй forцикл ( с переменной upperlimв контроле цикла) - нет. Есть ли способ, которым я могу изменить второй forцикл, чтобы он работал? Спасибо за ваше время.

Андрей
источник
4
Хм, даже for i in {0..$((upperlim))}; do echo $i; doneне работает
Бонси Скотт
и +1, потому что я считаю это поведение интересным
Бонси Скотт
возможный межсайтовый дубликат: stackoverflow.com/questions/169511/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Внешняя ссылка, которая отвечает на это: cyberciti.biz/faq/…
kon psych

Ответы:

62

Причиной этого является порядок, в котором вещи происходят в bash. Разбивка скобок происходит до раскрытия переменных. Чтобы достичь цели, вам нужно использовать цикл C в стиле:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
jordanm
источник
1
И работает , zshкак хорошо (но не для csh, tcsh).
математика
29

Чтобы выполнить это в своем стиле, используя только встроенные модули, вам нужно использовать eval:

d=12

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

Но с seq:

lowerlimit=0
upperlimit=12

for i in $(seq $lowerlimit $upperlimit)
do
echo $i
done

Лично я считаю использование seqболее читабельным.

Джоди С
источник
Для "встроенных модулей"? seqявляется внешней командой и недоступна везде, где есть bash.
Иордания
9
@jordanm: Для использования всех встроенных функций с bash. Затем я сказал «но с seq», признавая, что это не встроенный.
Джоди С
Тот факт, что расширение скобок встроено, здесь не проблема. readявляется встроенным, например, но нет никаких оснований для evalэтого.
Иордания
1
Встроенные функции не являются проблемой вообще. Я хотел предоставить решение для всех пользователей. Если вы хотите продолжать спорить об этом, возьмите его в чат; комментарии не годятся для такого рода вещей
Джоди С
8

Способ POSIX

Если вы заботитесь о переносимости, используйте пример из стандарта POSIX :

i=2
END=5
while [ $i -le $END ]; do
    echo $i
    i=$(($i+1))
done

Выход:

2
3
4
5

Вещи, которые не POSIX:

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
источник
1

Ваш подход не будет работать, так как в bash скобка-расширение происходит перед расширением параметра. Вы должны расширить переменную раньше.

Вы можете работать с eval :

upperlim=10
eval '
        for i in {0..'"$upperlim"'}
        do
                echo $i
        done
'

С циклом «Пока» :

upperlim=10
#with while
start=0
while [[ $start -le $upperlim ]]
do
    echo "$start"
    ((start = start + 1))
done

Также вы можете сделать это с помощью команды seq :

upperlim=10
#seq
for i in $(seq "$upperlim"); do
  echo "$i"
done

Если вы хотите работать с for i in {0..$upperlim}вами, вам нужно будет использовать kornshell. например:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
Хешав Севнундун
источник