В 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

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:


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.