В 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, оскільки мені ця поведінка цікава
Бонсі Скотт


Зовнішнє посилання, що відповідає на це: cyberciti.biz/faq/…
kon psych

Відповіді:


62

Причиною цього є порядок, в якому речі відбуваються в баш. Розширення дужки відбувається до розширення змінних. Для того, щоб досягти своєї мети, вам потрібно використовувати 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є зовнішньою командою, і вона недоступна скрізь.
Йорданм

9
@jordanm: Для використання всіх вбудованих файлів з bash. Тоді я сказав "але з seq", визнавши, що це не вбудований.
Джоді C

Факт розширення брекетів в цьому не є проблемою. readє вбудованим, наприклад, але для цього немає підстав eval.
Йорданм

1
Вбудовані взагалі не є проблематичними. Я хотів запропонувати запитувачу всебійне рішення. Якщо ви хочете продовжувати сперечатися з цього приводу, візьміть його до чату; коментарі не підходять для подібного роду
Jodie C

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 brace-розширення відбувається до розширення параметра. Вам потрібно розгорнути змінну раніше.

Ви можете попрацювати з 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.