More Than Five
More Than Five

Reputation: 10429

Converting lines of text to an array

In my bash script I have a variable, myvar which when echo'd prints multiple lines.

line1
line2
line3
line4
...

I want to convert the lines into an array and be able to iterate over it.

for i in "${myvar[@]}"
do
    echo "Line is: $i"
done

But this just gives:

Line is line1
line2
line3
line4
...

any tips?

Upvotes: 0

Views: 197

Answers (3)

Jason Heo
Jason Heo

Reputation: 10246

I think myvar just has one string, to make myvar having array each of lines.

#!/bin/bash

let -a myvar;

for line in `cat test.txt`
do
    myvar+=($line)
done

for i in "${myvar[@]}"
do
    echo "Line is: $i"
done

output

Line is: line1
Line is: line2
Line is: line3
Line is: line4

UPDATED - performance test

  • CentOS : 6.4 (runs on VirtualBox)
  • bash : 4.2.5
  • $filename is 40MB, contains 120k lines and each of line approximately 300 bytes long.

  • Q1

    for line in `cat $filename`
    do
        myvar+=($line)
    done
    
  • Q2

    myvar=(`cat $filename`)
    
  • Q3

    mapfile -t myvar < "$filename"
    

Results

  • Q1 : 28 sec.
  • Q2 : 11 sec.
  • Q3 : < 1 sec. (Wow~!)

Upvotes: 0

gniourf_gniourf
gniourf_gniourf

Reputation: 46903

I don't know why you have a variable with newlines; maybe you should review your design!

Anyways, in bash 4, the cleanest and most efficient way is to use mapfile:

myvar=$'line1\nline2\nline3\nline 4 with spaces in it\nline 5 with no trailing newline'

mapfile -t myarray <<< "$myvar"

for i in "${myarray[@]}"; do
    echo "Line is: $i"
done

There's another possibility, fiddling with IFS, but that's too ugly for this purpose.

Notice that, unlike the accepted answer (which shows terrible bash practices — you guys should definitely stop supporting bad practices and broken codes), this works fine with spaces.

Now, if your variable myvar is in fact obtained from a file (since you accepted the answer that shows this, it might be your case), to directly obtain the content of the file file.txt in an array, the fields of which being the lines of the file, use:

mapfile -t myarray < "file.txt"

for i in "${myarray[@]}"; do
    echo "Line is: $i"
done

And it will be more efficient too.

Upvotes: 1

Maciej Sz
Maciej Sz

Reputation: 12045

If your variable contains new lines as escaped character \n, then you need to echo -e to make it an array:

#!/usr/bin/env bash

myvar="Line1\nLine2\nLine3";
arr=$(echo -e $myvar)

for i in $arr
do
    echo $i
done

Upvotes: 0

Related Questions