0

I am trying to read the last two lines of a file in an array of length two.

Consider the file a.txt

bar
second line
hello world
foo bar fubar

I tried

lines=($(tail -n 2 a.txt))

but this results in an array of length 5, each containing a single word. I read the post Creating an array from a text file in Bash but fail to go from there to reading only the last two lines. Please note that efficiency (execution time) matters for my needs.

I am on Mac OS X using Terminal 2.6.1

codeforester
  • 39,467
  • 16
  • 112
  • 140
Remi.b
  • 17,389
  • 28
  • 87
  • 168

3 Answers3

2

You can use the mapfile command in bash for this. Just tail the last 2 lines and store them in the array

mapfile -t myArray < <(tail -n 2 file)
printf "%s\n" "${myArray[0]}"
hello world
printf "%s\n" "${myArray[1]}"
foo bar fubar

See more on the mapfile builtin and the options available.


If mapfile is not available because of some older versions of bash, you can just the read command with process-substitution as below

myArray=()
while IFS= read -r line
do 
    myArray+=("$line") 
done < <(tail -n 2 file)

and print the array element as before

printf "%s\n" "${myArray[0]}"
Inian
  • 80,270
  • 14
  • 142
  • 161
  • Hum.... I am on MAC using Terminal version 2.6.1 (info edited on post) (`GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)`). I don't have the mapfile builtin unfortunately. Thanks anyway – Remi.b Sep 14 '17 at 17:22
  • @Remi.b: Check my update which should work on older versions also! – Inian Sep 14 '17 at 17:26
  • 2
    @Remi.b: then use two `read` statements: `lines=(); { IFS= read -r 'lines[0]'; IFS= read -r 'lines[1]'; } < <(tail -n2 file)`. – gniourf_gniourf Sep 14 '17 at 17:28
0

try following once and let me know if this helps you.

array[0]=$(tail -2 Input_file | head -1)
array[1]=$(tail -1 Input_file)

Output will be as follows.

echo ${array[0]}
hello world
echo ${array[1]}
foo bar fubar
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • `tail -2 .. | head -1` is a bit of an anti-pattern! when you can do it more directly. Also I see no reason you want to store the values from index `1` when you can do it from `0` – Inian Sep 14 '17 at 17:19
  • Thanks Inian, actually why I have done tail -2 | head -1 tried to do in OP's style itself. Yes, we could do from array[0] and array[1], I simply given examples, let me fix it now. Thank you sir for your guidance here :) – RavinderSingh13 Sep 14 '17 at 17:21
0

You can use it like this:

# read file in an array
mapfile -t ary < file

# slice last 2 elements
printf '%s\n' "${ary[@]: -2}"

If you don't have mapfile then use this while loop to populate your array:

ary=()
while read -r; do
   ary+=("$REPLY")
done < file

printf '%s\n' "${ary[@]: -2}"

Output:

hello world
foo bar fubar
anubhava
  • 761,203
  • 64
  • 569
  • 643