Чи можу я використовувати змінну в розширенні дужки Bash?


10

Нижче наведено якийсь псевдо-код для того, що я намагаюся досягти:

#!/bin/bash

# I already have the variable below figured out (positive integer):
numlines=$([returns number of lines containing specific characters in a file])

# This is basically what I want to do with it:
for i in {1..$numlines}; do
    # the part below is already figured out as well:        
    do some other stuff
done

Я можу це добре виконати з командного рядка, вставивши фактичне число у послідовності `{1..n} '. Мені просто потрібно знати, чи можна включити змінну сюди і як це робити.

  • Я спробував exportце
  • Я спробував помістити саму змінну в фігурні дужки всередині послідовності: {1..${numlines}}
  • Я спробував скласти це в подвійних лапках, сподіваючись, що він розшириться: {1.."$numlines"}
  • Я спробував уникнути $:{1..\$numlines}

Чи потрібно мені використовувати set -[something]команду, щоб ця змінна розширилася? Я навіть спробував деякі форми використання eval... все безрезультатно.

Мені просто потрібно знати, чи є щось просте або незрозуміле, чого я пропускаю, або якщо це навіть можливо, перш ніж я витрачу більше часу на це.

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


Відповіді:


11

На жаль, немає можливості використовувати змінну в цьому розширенні (AFAIK), оскільки змінна розширення відбувається після розширення дужок.

На щастя, є інструмент, який виконує ту саму роботу.

for i in $(seq 1 $numlines); do
    # stuff
done

seqє від GNU coreutils; поняття не маю, як це зробити в POSIX.


1
(Плюс 1). seqпідходить для систем GNU і, якщо я правильно пригадую, останньої ОСX. В інших системах BSD можна використовувати замість jot .
John1024

seqпрацює чудово. Дякую вам за вашу швидку відповідь.
рубінові перила

Це не було частиною мого питання - але який синтаксис (якщо такий є) для цього в зворотному порядку, наприклад {16..1}? $(seq $numlines 1)не працює. Я здогадуюсь, що завжди man seq, але просто цікаво, чи хтось знав у верхній частині голови.
rubynorails

1
Щойно з'ясував, як це зробити в зворотному порядку за цим посиланням -for i in $(seq $numlines -1 1)
rubynorails

seq ${numlines} -1 0
DopeGhoti

10

Звичайно. Якщо ви хочете, щоб цикл for, який збільшує цілочисленну змінну, використовуйте форму forциклу, що збільшує цілочисленну змінну (або більш загально виконує арифметику на змінних (цих) циклу).

for ((i=1; i<=numlines; i++)); do  done

Ця конструкція працює в bash (і ksh93 і zsh), але не в звичайному sh. У звичайному sh, використовуйте цикл while та [ … ]конструкцію test ( ).

i=1
while [ "$i" -le "$numlines" ]; do
  
  i=$((i+1))
done

8

Якщо ви повинні уникати seq, що, як зазначає Том Хант, здається, звичайним рішенням для цього, то, evalбезумовно, це можна зробити (хоча, я б не рекомендував це):

eval 'for i in {1..'$numlines'}; do echo $i; done'

Ви можете залишатись POSIX, уникаючи {} розширення і просто виконувати математичні та цілі порівняння на $numlines:

while [ ! "$numlines" -eq 0 ]; do
     echo "$numlines"
     : $((numlines-=1))
done

Поза POSIX, bashа kshй zshтакож має C-стиль forпетля:

for((i=0; i<numlines; i++)); do echo $i; done

1
Я дуже ціную цю відповідь також. Хоча я seqпрацював чудово за моїм сценарієм і здавався найпростішим рішенням, добре знати, що існують інші (навіть POSIX) альтернативи. Дякую за це
rubynorails

2
Дійсно немає причин використовувати eval; якщо у вас є розширення дужок, у вас є цикл у стилі С.
чепнер

@PSkocik - Якби я міг вибрати 2 відповіді, я також вибрав би цю. Коли я натрапив на те, що мені потрібно це зробити в зворотному порядку, ваш evalприклад був найпростішим і врятував би мене від необхідності шукати альтернативний спосіб зробити це за допомогою seq. whileПетля трохи громіздким для мене. Мені подобається, щоб речі були короткими і солодкими, і я ніколи не міг змусити forцикл стилю C працювати, надаючи iзначення 0 або 1. Він ніколи не повертався правильно і завжди був трохи відключений. Я впевнений, що це може бути налаштовано на правильну роботу, але, безумовно, це корисні рішення.
rubynorails

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