Скрипт оболонки "for" циклу синтаксису


191

Я настав на роботу наступне:

for i in {2..10}
do
    echo "output: $i"
done

Вона виробляє купу ліній output: 2, output: 3так далі.

Однак, намагаюся виконати наступне:

max=10
for i in {2..$max}
do
    echo "$i"
done

виробляє наступне:

output: {2..10}

Як я можу змусити компілятор зрозуміти, що він повинен трактувати $ max як інший кінець масиву, а не частину рядка?


2
яку систему та оболонку ви використовуєте? Яка система goofy має sh або bash, але не має seq, coreutil?
whatsisname

11
FreeBSD не робить.
Ніцше-джу

echo "$iповинно бути echo "$i"- не вирішить проблему.
Дейв Джарвіс

Низький стиль ніт: я зазвичай бачу doі thenключові слова в тому ж рядку, що forі ifвідповідно. Напр.,for i in {2..10}; do
платний ботанік

Відповіді:


234

Розширення дужок, {x..y} виконується перед іншими розширеннями, тому ви не можете використовувати це для послідовностей змінної довжини.

Замість цього використовуйте seq 2 $maxметод як вказаний користувачем mob .

Отже, для вашого прикладу це було б:

max=10
for i in `seq 2 $max`
do
    echo "$i"
done

Немає вагомих причин використовувати зовнішню команду, таку як seqпідрахунок і збільшення чисел у циклі for, тому рекомендується уникати використання seq. Ця команда залишається для сумісності зі старим bash. Вбудовані команди досить швидкі. for (( EXP1; EXP2; EXP3 )) ...
мельник

13
@miller for (( ... ))синтаксис не є POSIX, а це означає, що він не працює з таких речей, як Alpine Linux. seqробить.
Wernight

@Wernight Не лише альпійський Linux; #!/bin/shє Dash в Debian / Ubuntu.
Франклін Ю.

72

Спробуйте версію арифметичного виразу for:

max=10
for (( i=2; i <= $max; ++i ))
do
    echo "$i"
done

Це доступно в більшості версій bash, а також має бути сумісним з оболонками Bourne (sh).


1
@ Flow: Гм, я просто спробував це на декількох системах (на базі Linux та BSD) з #! / Bin / sh, і це працювало чудово. Запрошений під bash і конкретно під / bin / sh, все ще працює. Можливо, версія має значення? Ви на якомусь старому Unix?
система ПАУЗА

8
Дуже небагато систем мають виділений sh, замість цього він робить посилання на іншу оболонку. В ідеалі, така оболонка викликається як shби тільки підтримувати ці функції в стандарті POSIX, але за замовчуванням нехай деякі зі своїх додаткових функцій через. С-стиль для-циклу не є функцією POSIX, але може перебувати в shрежимі фактичної оболонки.
чепнер

27

Крок циклу вручну:

i = 0
max = 10
поки [$ i -lt $ max]
робити
    ехо "вихід: $ i"
    true $ ((i ++))
зроблено

Якщо вам не потрібно бути повністю POSIX, ви можете використовувати арифметику для циклу:

max = 10
for ((i = 0; i <max; i ++)); робити відлуння "вихід: $ i"; зроблено

Або використовувати jot (1) у системах BSD:

для i в $ (jot 0 10); робити відлуння "вихід: $ i"; зроблено

3
true $(( i++ ))працює не у всіх випадках, тому більшість портативних буде true $((i=i+1)).
Потік

напівколонка не повинна надходити "для ((i = 0; i <max; i ++));"
logan

9

Існує більше ніж один спосіб зробити це.

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done

7
Ризик безпеки, оскільки evalбуде оцінювати все, що ви встановили max. Подумайте max="2}; echo ha; #", тоді замініть echo haчимось більш руйнівним.
чепнер

6
(S) він встановив максимум на 10. Без ризику.
Конрад Мейєр

9

Якщо seqкоманда доступна у вашій системі:

for i in `seq 2 $max`
do
  echo "output: $i"
done

Якщо немає, то використовуйте бідняк seqз perl:

seq=`perl -e "\$,=' ';print 2..$max"`
for i in $seq
do
  echo "output: $i"
done

Слідкуйте за цитатами.


Я щойно перевірив це; не здається, що це так.
ейканал

5

Це спосіб:
Bash:

max=10
for i in $(bash -c "echo {2..${max}}"); do echo $i; done

Вище Bash спосіб буде працювати kshі zshтеж, коли bash -cзамінюється ksh -cабо zsh -cвідповідно.

Примітка: for i in {2..${max}}; do echo $i; doneпрацює в zshі ksh.


4

Ми можемо повторити цикл, як програмування на C.

#!/bin/bash
for ((i=1; i<=20; i=i+1))
do 
      echo $i
done

2

Тут він працював на Mac OS X.

Він включає приклад дати BSD, як збільшити та зменшити дату також:

for ((i=28; i>=6 ; i--));
do
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat
done

2

Ну, оскільки в мене не було seqвстановленої команди в моїй системі (Mac OS X v10.6.1 (Snow Leopard)), я whileзамість цього використовував цикл:

max=5
i=1

while [ $max -gt $i ]
do
    (stuff)
done

* Знизує плечима * Що б не працювало.


2
послідовно новий. Про це я дізнався лише кілька місяців тому. Але ви можете використовувати цикл 'для' !! Недоліком функції "while" є те, що вам потрібно пам’ятати, щоб збільшити лічильник десь усередині циклу, інакше цикл вниз.
система ПАУЗА

1

Це все робити {1..8}і повинно бути POSIX. Вони також не зламаються, якщо ви помістите умовне continueв петлю. Канонічний спосіб:

f=
while [ $((f+=1)) -le 8 ]
do
  echo $f
done

Інший спосіб:

g=
while
  g=${g}1
  [ ${#g} -le 8 ]
do
  echo ${#g}
done

та інше:

set --
while
  set $* .
  [ ${#} -le 8 ]
do
  echo ${#}
done

1

Використання:

max=10
for i in `eval echo {2..$max}`
do
    echo $i
done

Вам потрібно чіткий виклик 'eval' для переоцінки {} після підстановки змінної.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.