Como ler diferentes linhas de um arquivo para diferentes variáveis?

14

Eu gostaria de ler diferentes linhas de um arquivo de texto para diferentes variáveis. Por exemplo

input.txt:

line1 foo foobar bar
line2 bar
line3 foo
line4 foobar bar

Quero que este resultado a ser armazenados em variáveis var1, var2, var3e var4de tal forma que

var1=line1 foo foobar bar
var2=line2 bar

e assim por diante.

Alguém poderia me dizer como é feito. Eu tentei usar evalem um loop for. Não parece funcionar.

neet
fonte
3
Essa é uma péssima abordagem. Desde basicamente a única razão para variáveis conjunto é fazer algo com eles, e uma vez que há um grande número de ferramentas especificamente concebidas para fazer as coisas com cada linha de texto em um arquivo (Awk, Sed, grep, cut, et. Al.), é muito melhor fazer apenas o que você precisa fazer. Não microgerencie em um script de shell; orquestrar ferramentas para realizar o trabalho.
Curinga

Respostas:

20

Você faria:

unset -v line1 line2
{ IFS= read -r line1 && IFS= read -r line2; } < input.txt

Ou:

{ line1=$(line) && line2=$(line); } < input.txt

(menos eficiente, pois lineraramente é incorporado e a maioria dos shells precisa se bifurcar para implementar a substituição de comandos. linetambém não é mais um comando padrão).

Para usar um loop:

unset -v line1 line2 line3
for var in line1 line2 line3; do
  IFS= read -r "$var" || break
done < input.txt

Ou para definir automaticamente os nomes das variáveis ​​como line<++n>:

n=1; while IFS= read -r "line$n"; do
  n=$((n + 1))
done < input.txt

Observe que bashsuporta variáveis ​​de matriz e um readarraybuiltin para ler linhas em uma matriz:

readarray -t line < input.txt

Observe, no entanto, que, ao contrário da maioria dos outros shells, os bashíndices da matriz começam em 0 e não 1 (herdados de ksh), portanto a primeira linha estará dentro ${line[0]}, não ${line[1]}(embora como o @Costas tenha mostrado , você pode fazer readarray(aka mapfile) começar a escrever os valores no índice 1 ( bashmatrizes também contrárias à maioria das outras conchas sendo matrizes esparsas ) com -O 1).

Consulte também: Entenda "IFS = read -r line"?

Stéphane Chazelas
fonte
12

Eu ofereceria usar matriz para essas tarefas

mapfile -t -O 1 var <input.txt

assim você vai ter cada linha ${var[1]}, ${var[2]}e assim por diante

Costas
fonte
Este one-liner funciona muito bem. Resolvido o problema para mim.
Matt Zabojnik
0

Não é exatamente o que você solicitou, mas pode funcionar para suas necessidades. Você pode serializar os dados com o Awk. Observe que isso será interrompido se seu $ 1 não for um nome de variável válido:

awk '
function quote(str,   d, m, x, y, z) {
  d = "\47"; m = split(str, x, d)
  for (y in x) z = z d x[y] (y < m ? d "\\" d : d)
  return z
}
{
  print $1 "=" quote($0)
}
' input.txt > /tmp/input.sh
. /tmp/input.sh

Resultado:

$ echo "$line1"
line1 foo foobar bar
Steven Penny
fonte
Este é um código seriamente estranho! Parece que você está usando o awk para transformar todo o arquivo de entrada em um script bash, que você origina. Eu tenho uma vaga idéia do que quote () está fazendo. Nomes de variáveis ​​mais descritivos ajudariam. Você poderia explicar as coisas um pouco mais?
Joe