Shell Read Lines of File Into Array

đź“… Oct 28, 2020
Suppose y'all desire to populate a Fustigate array with a list of values or words. Is in that location a convenient manner to practise this without manually specifying each individual alphabetize for the array?

Yes, there is! Using read or mapfile, nosotros can declare and populate a Bash array in one go.

Populating the Array

The read command has the -a option that allows us to populate the given array with a list of whitespace-delimited values. (The IFS value determines the delimiter, which is whitespace by default.) The array is populated starting at index 0. The last value provided becomes the final element in the array.

Similar this:

read -a arrNumber two 45 67 454 77.77 89 10000 56000 32768 -36 -89 -800 0

Entering read -a arrNumber will prompt you to enter a series of values, each separated by a space. Press Enter to conclude the value entry, and you will return to the prompt.

To view the contents of the array, utilise

echo ${arrNumber[@]}

or

echo ${arrNumber[*]}

Both will show the same contents of the array, but in that location is a difference between [@] and [*].

  • [@]  Prove all elements as split up values.
  • [*]    Prove all elements every bit a single string.

For more information about the divergence between [@] and [*], delight consult the article Put Filenames in Bash Array.

Also, take note that the array name is case-sensitive. In this instance, ${arrNumber[@]} works, but ${arrNUmber[@]} (with an upper case U) does non and only returns a bare line.

Accessing Elements

Each element is located at an index, starting at 0, from left to right.

2 45 67 454 77.77 89 10000 56000 32768 -36 -89 -800 0

two, is at index 0. 45 is at index 1, 77.77 is at index 4. -800 is at index 11. Place the alphabetize in square brackets to get its element from the array.

repeat ${arrNumber[0]}   // Returns 2 echo ${arrNumber[1]}   // 45 echo ${arrNumber[4]}   // 77.77 echo ${arrNumber[11]}  // -800

Negative Indexes

Nosotros can fifty-fifty utilise negative indexes that count from the end of the array. Notation that we cannot apply something like -0.

echo ${arrNumber[-1]}   // Returns 0, which is the concluding element in the array. repeat ${arrNumber[-two]}   // -800 echo ${arrNumber[-11]}  // 67 echo ${arrNumber[-12]}  // 45 echo ${arrNumber[-13]}  // ii, the start element in the array repeat ${arrNumber[-14]}  // Mistake: bash: arrNumber: bad array subscript

If we try to use a negative index that would get beyond 0 (into the negative numbers), then bash returns a bad array subscript fault message.

Populate with Strings

In both cases, the array automatically populated with a serial of data. We are not limited to numbers. How about words and strings of words?

read -a arrText this is a 'Examination involving math questions'

If we view the contents of the arrText,

repeat ${arrText[@]}

we encounter the text we entered:

this is a 'Test involving math questions'

Accept note that the unmarried quotes are preserved.

What do yous retrieve the last element in the array will be? Volition it be a single word or will it be a cord enclosed in unmarried quotes?

Allow's find out by returning the last element using the alphabetize -1.

repeat ${arrText[-1]} questions'

Hmm. It is a single word questions' including the ending single quote. The internal field separator (IFS) determines what separates words, not quotes. We demand to modify the IFS to something that is not a space, such as a comma.

ifs_saved=$IFS   // Save the current IFS so we can reset it after IFS=,  // Ready to a comma character  read -a arrText this,is,a,'Test involving math questions'

If we view the assortment,

echo ${arrText[@]} this is a 'Test involving math questions'

nosotros meet what nosotros entered. Only this time, if we go the last element from the assortment using index -1,

repeat ${arrText[-1]} 'Test involving math questions'

we see 'Exam involving math questions' as a single chemical element including the quotes. In fact, nosotros do not need to use quotes at all since we changed the IFS to delimit by commas instead of whitespace.

read -a arrText this,is,a,Test involving math questions

We see the aforementioned effect merely without single quotes:

echo ${arrText[@]} this is a Test involving math questions  echo ${arrText[-one]} Examination involving math questions

The single quotes were treated as part of the string, not as string delimiters.

Restore the IFS

Set the IFS back to its original value.

IFS=$ifs_saved

Or, close and reopen the terminal to reset the IFS.

Populating from a File

"Tin we fill an array with words from a file?"

Yep. First of all, the easiest manner to make full an empty array (or overwrite an existing ane) is to exercise this:

arrText=($(cat words.txt))

Our list of words is located in a text file named words.txt where each word exists on its own line. The command substitution must exist inside some other ready of parentheses to announce an array.

apple cider Burma Shave pastel attic kitchen countertop 50s-doo-wop  echo ${arrText[@]} apple cider Burma Shave pastel attic kitchen countertop 50s-doo-wop

We see that the assortment has been populated. Newlines act every bit delimiters in this instance, but permit's see if that is true with kitchen countertop, which should be a single line of text, not two elements.

echo ${arrText[6]} kitchen  echo ${arrText[7]} countertop

Uh-oh, we meet two divide elements. It's the IFS delimiting by all whitespace once again! We need to change information technology to a newline character only.

Changing IFS to Newline

This is trickier than it sounds. Neither of the following volition work:

IFS='\due north' IFS=\north

Even though \n represents a newline, both remove the lowercase n character.

IFS=$'\due north' echo ${arrText[@]} apple tree cider Burma Shave pastel cranium          kitche cou tertop          50s-doo-wop

This is not what nosotros want. Enclose a manual newline (printing the Enter key on the keyboard) and enclose that within quotes.

IFS='
> '

This volition delimit newlines from the control prompt. If entered in a script, use this:

IFS='   // Press Enter to enter a newline '

Another way is to employ this:

IFS=$'\n'

However, the success can vary by distribution and might still remove lowercase n characters, then test it on your Linux arrangement starting time earlier relying upon it.

IFS=$'\due north' arrText=($(cat words.txt)) echo ${arrText[@]} apple cider Burma Shave pastel attic          kitchen countertop          50s-doo-wop

Skilful! All is working.

echo ${arrText[6]} kitchen countertop

We encounter that kitchen countertop is returned equally a single line of text as it exists in the file.

Using read

With read, we should be able to enter the post-obit to populate an array with lines of text from a file:

read -a arrText < words.txt  declare -p arrText declare -a arrText=([0]="apple")

However, declare -p arrText merely shows the showtime line from the file.

Another manner is to utilize a while loop. Nosotros will use a script for this.

#!/bin/bash  while read -r line do     arrText+=("$line") done < words.txt  echo ${arrText[@]} echo ${arrText[6]}

The -r option is used with read even though -a volition as well work. Option -r preserves any escaped backslash characters.

fustigate test.sh apple cider Burma Shave pastel cranium kitchen countertop 50s-doo-wop kitchen countertop

We see that kitchen countertop appears as its own element instead of two.

Using mapfile

An fifty-fifty easier way is to use mapfile.

mapfile -t arrText < words.txt echo ${arrText[@]} apple cider Burma Shave pastel attic kitchen countertop 50s-doo-wop

No demand for loops. mapfile takes each line of text from the text file and stores it into the array named arrText starting at index 0. The -t choice removes whatever abaft newlines from the line stored in the array. We can use mapfile without -t.

mapfile arrText < words.txt echo ${arrText[@]} apple tree cider Burma Shave pastel attic kitchen countertop 50s-doo-wop

By default, mapfile delimits by newlines, and so there is no need to change the IFS as with read.

mapfile arrKitty hello kitty wuz heer

Press CTRL+D to end input and return to the control prompt.

repeat ${arrKitty[@]} hello kitty wuz heer  repeat ${arrKitty[-1]} wuz heer

We encounter that spaces are preserved every bit part of each string. Between read and mapfile, mapfile is a more user-friendly choice for populating an array with values. Of course, there is no "correct" way. Information technology depends upon your goals.

mapfile is a Fustigate builtin command, so it does not take a dedicated man page. Please bank check a usage reference for more than information most mapfile.

Conclusion

Bash arrays can be somewhat counter-intuitive due to seemingly awkward syntax, but hopefully the ideas presented here volition help you populate arrays with values should the demand ascend.

Take fun!

leelattlyined.blogspot.com

Source: https://delightlylinux.wordpress.com/2020/10/28/bash-read-into-an-array/

0 Response to "Shell Read Lines of File Into Array"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel