Posso ter uma variável em uma condição / sequência Bash “para loop”?

6

Eu não consegui pensar em uma maneira melhor de redigir o título da pergunta. Eu sei que tem que haver uma resposta fácil ou uma alternativa simples para fazer o que eu estou tentando fazer, mas eu simplesmente não consigo fazer nada no momento.

Abaixo está um tipo de pseudo-código para o que estou tentando realizar:

#!/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

Eu posso executá-lo bem a partir da linha de comando, inserindo o número real na sequência '{1..n}'. Eu só preciso saber se é possível incluir uma variável aqui e como fazê-lo.

  • Eu tentei export it
  • Eu tentei colocar a própria variável entre chaves dentro da sequência: {1..${numlines}}
  • Tentei colocá-lo entre aspas duplas, esperando que ele se expandisse: {1.."$numlines"}
  • Eu tentei escapar do $ : {1..\$numlines}

Preciso usar um comando set -[something] para que essa variável seja expandida? Eu até tentei algumas formas de usar eval ... tudo sem sucesso.

Eu só preciso saber se há algo simples ou obscuro que estou perdendo ou se isso é possível antes que eu perca mais tempo com isso.

Eu poderia criar uma maneira muito, realmente de fazê-lo funcionar, se necessário, mas eu gostaria de evitar isso, se possível, e aprender o caminho certo a seguir fazendo isso.

    
por rubynorails 20.11.2015 / 00:20

3 respostas

10

Infelizmente, não há como usar uma variável nessa expansão (AFAIK), já que a expansão de variáveis ocorre após a expansão de chaves.

Felizmente, há uma ferramenta que faz o mesmo trabalho.

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

seq é de GNU coreutils; Não faço ideia de como fazer isso no POSIX.

    
por 20.11.2015 / 00:27
8

Se você deve evitar seq , que como Tom Hunt aponta parece ser a solução usual para isso, então um eval definitivamente pode fazê-lo (embora, eu não encorajaria isso):

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

Você pode manter o POSIX evitando a {} expansão e fazer comparações matemáticas e inteiras em $numlines :

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

Fora do POSIX, bash e ksh e zsh também têm% de co-lo% no estilo C:

for((i=0; i<numlines; i++)); do echo $i; done
    
por 20.11.2015 / 00:33
7

Claro. Se você quiser um loop for que incremente uma variável inteira, use o formato for loop que incrementa uma variável inteira (ou mais geralmente realiza aritmética na (s) variável (s) de loop).

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

Esta construção funciona no bash (e ksh93 e zsh), mas não na forma sh simples. Em sh simples, use um loop while e a construção test ( [ … ] ).

i=1
while [ "$i" -le "$numlines" ]; do
  …
  i=$((i+1))
done
    
por 20.11.2015 / 02:36