17

I would like to read different lines of a text file to different variables. For example

input.txt:

line1 foo foobar bar
line2 bar
line3 foo
line4 foobar bar

I want this result to be stored in variables var1, var2, var3 and var4 such that

var1=line1 foo foobar bar
var2=line2 bar

and so on.

Could someone please tell me how it is done. I tried to use eval in a for loop. It doesn't seem to work.

GAD3R
  • 66,769
neet
  • 179

3 Answers3

21

You'd do:

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

Or:

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

(less efficient as line is rarely built-in and most shells need to fork to implement command substitution. line is also no longer a standard command).

To use a loop:

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

Or to automatically define the names of the variables as line<++n>:

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

Note that bash supports array variables and a readarray builtin to read lines into an array:

readarray -t line < input.txt

Note however that contrary to most other shells, bash array indices start at 0 not 1 (inherited from ksh), so the first line will be in ${line[0]}, not ${line[1]} (though as @Costas has shown, you can make readarray (aka mapfile) start writing the values at indice 1 (bash arrays also contrary to most other shells' being sparse arrays) with -O 1).

See also: Understand "IFS= read -r line"?

14

I'd offer to use array for such task(s)

mapfile -t -O 1 var <input.txt

so you'll have each line in ${var[1]}, ${var[2]} and so on

Costas
  • 14,916
0

This is not strictly what you asked for, but it might work for your needs. You can serialize the data with Awk. Note that this will break if your $1 is not a valid variable name:

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

Result:

$ echo "$line1"
line1 foo foobar bar
Zombo
  • 1
  • 5
  • 44
  • 63
  • This is seriously strange code! It appears that you're using awk to turn the whole input file into a bash script which you then source. I have a vague idea of what quote() is doing. More descriptive variable names would help. Could you explain things a bit more? – Joe Jan 28 '17 at 06:36