Comment lire différentes lignes d'un fichier dans différentes variables?

14

Je voudrais lire différentes lignes d'un fichier texte dans différentes variables. Par exemple

input.txt:

line1 foo foobar bar
line2 bar
line3 foo
line4 foobar bar

Je veux que ce résultat à stocker dans des variables var1, var2, var3et de var4telle sorte que

var1=line1 foo foobar bar
var2=line2 bar

etc.

Quelqu'un pourrait-il me dire comment cela se fait? J'ai essayé d'utiliser evaldans une boucle for. Cela ne semble pas fonctionner.

neet
la source
3
C'est une mauvaise approche. Depuis essentiellement la seule raison de variables définies est de faire quelque chose avec eux, et comme il y a un grand nombre d'outils spécialement conçus pour faire des choses avec chaque ligne de texte dans un fichier (awk, sed, grep, cut, et. Al.), c'est beaucoup mieux de faire juste ce que vous devez faire. Ne pas microgérer dans un script shell; orchestrez les outils pour faire le travail.
Wildcard

Réponses:

20

Vous feriez:

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

Ou:

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

(moins efficace que line est rarement intégré et la plupart des shells doivent se bifurquer pour implémenter la substitution de commandes. linen'est plus non plus une commande standard).

Pour utiliser une boucle:

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

Ou pour définir automatiquement les noms des variables comme line<++n>:

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

Notez que bashprend en charge les variables de tableau et une fonction readarrayintégrée pour lire les lignes dans un tableau:

readarray -t line < input.txt

Notez cependant que contrairement à la plupart des autres shells, les bashindices de tableau commencent à 0 et non à 1 (hérité de ksh), donc la première ligne sera dans ${line[0]}, pas ${line[1]}(bien que comme @Costas l'a montré , vous pouvez faire readarray(aka mapfile) commencer à écrire les valeurs à indice 1 ( bashtableaux également contraires à la plupart des autres obus étant clairsemés tableaux ) avec -O 1).

Voir aussi: Comprendre "IFS = read -r line"?

Stéphane Chazelas
la source
12

Je proposerais d'utiliser le tableau pour de telles tâches

mapfile -t -O 1 var <input.txt

vous aurez donc chaque ligne ${var[1]}, ${var[2]}et ainsi de suite

Costas
la source
Cette doublure fonctionne très bien. Résolu le problème pour moi.
Matt Zabojnik
0

Ce n'est pas strictement ce que vous avez demandé, mais cela pourrait répondre à vos besoins. Vous pouvez sérialiser les données avec Awk. Notez que cela se cassera si votre $ 1 n'est pas un nom de variable valide:

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

Résultat:

$ echo "$line1"
line1 foo foobar bar
Steven Penny
la source
C'est un code vraiment étrange! Il semble que vous utilisiez awk pour transformer tout le fichier d'entrée en un script bash que vous sourcez ensuite. J'ai une vague idée de ce que fait quote (). Des noms de variables plus descriptifs seraient utiles. Pourriez-vous expliquer un peu plus les choses?
Joe