bash read from file and store in array [duplicate] - arrays

This question already has answers here:
Creating an array from a text file in Bash
(7 answers)
Closed 5 years ago.
Let's say i have a file that looks like this:
element1,element2
element3,element4
element5,element6
How can I read this file in bash and store it in an array as follows:
array={element1,element2,element3,element4,element5,element6}
Can someone help me with the code? Thanks!

You can ignore read altogether and simply use redirection after setting IFS, e.g.
$ IFS=$', \t\n'; a=($(<file)); declare -p a
declare -a a='([0]="element1" [1]="element2" [2]="element3" [3]="element4" \
[4]="element5" [5]="element6")'

Instead of reading line by line, then spliting by comma, you could do:
IFS=,$'\n' read -d '' -r -a array <file
This will:
use NUL character as line delimiter (-d ''), and this way (if your file does not contain null characters) read the complete file at once
split the "line" (i.e. the complete file) in fields using IFS, which is set to comma and newline, IFS=,$'\n'
store all words/elements in array.
Output:
$ printf "%s\n" "${arr[#]}"
element1
element2
element3
element4
element5
element6

You can use this bash code:
while IFS='' read -r line || [[ -n "$line" ]]; do
array+=("$line")
done < "$1"
echo ${array[#]}
This read the content of the file that you specify by argument line and reads line by line while stores the values in a bash array.
Bye!

Related

Bash. Split text to array by delimiter [duplicate]

This question already has answers here:
How to split a string into an array in Bash?
(24 answers)
Closed 1 year ago.
Can somebody help me out. I want to split TEXT(variable with \n) into array in bash.
Ok, I have some text-variable:
variable='13423exa*lkco3nr*sw
kjenve*kejnv'
I want to split it in array.
If variable did not have new line in it, I will do it by:
IFS='*' read -a array <<< "$variable"
I assumed the third element should be:
echo "${array[2]}"
>sw
>kjenve
But with new line it is not working. Please give me right direction.
Use readarray.
$ variable='13423exa*lkco3nr*sw
kjenve*kejnv'
$ readarray -d '*' -t arr < <(printf "%s" "$variable")
$ declare -p arr
declare -a arr=([0]="13423exa" [1]="lkco3nr" [2]=$'sw\nkjenve' [3]="kejnv")
mapfile: -d: invavlid option
Update bash, then use readarray.
If not, replace separator with zero byte and read it element by element with read -d ''.
arr=()
while IFS= read -d '' -r e || [[ -n "$e" ]]; do
arr+=("$e")
done < <(printf "%s" "$variable" | tr '*' '\0');
declare -p arr
declare -a arr=([0]="13423exa" [1]="lkco3nr" [2]=$'sw\nkjenve' [3]="kejnv")
You can use the readarray command and use it like in the following example:
readarray -d ':' -t my_array <<< "a:b:c:d:"
for (( i = 0; i < ${#my_array[*]}; i++ )); do
echo "${my_array[i]}"
done
Where the -d parameter defines the delimiter and -t ask to remove last delimiter.
Use a ending character different than new line
end=.
read -a array -d "$end" <<< "$v$end"
Of course this solution suppose there is at least one charecter not used in your input variable.

How to write a shell script which accepts array in the command line and outputs the sum of it [duplicate]

This question already has answers here:
How to initialize a bash array with output piped from another command? [duplicate]
(3 answers)
Closed 6 years ago.
I am new to arrays in Bash scripting. I need to write a script which accepts an array from standard input on the command line. and outputs the sum of it to the user.
Here is the logic, but how can I convert it into shell script to be used in command line?
read -a array
tot=0
for i in ${array[#]}; do
let tot+=$i
done
echo "Total: $tot"
Any help is appreciated.
You're close! Try this instead:
IFS=$'\n' read -d '' -r -a array
total=0
for i in "${array[#]}"; do
((total += i))
done
When you're reading $array from stdin with read -a, you're only getting the first line.
IFS=$'\n' changes Bash's Internal Field Separator to the newline symbol (\n) so that each line is seen as a separate field, rather than looking for tokens separated by whitespace. -d '' makes read not stop reading at the end of each line. ((total += i)) is a shorter/cleaner way to do math.
Here's it running:
$ seq 1 10 | ./test.sh
Total: 55
#!/bin/bash
calcArray() {
local total=0
for i ;do
let total+=$i
done
echo "${total}"
}
From your terminal do this source scriptName .
calcArray 1 2 3 4 5
Don't quote the args.
In your .bashrc put source scriptName, so you can always run calcArray args , without source scriptName again

How can I handle an array where elements contain spaces in Bash?

Let's say I have a file named tmp.out that contains the following:
c:\My files\testing\more files\stuff\test.exe
c:\testing\files here\less files\less stuff\mytest.exe
I want to put the contents of that file into an array and I do it like so:
ARRAY=( `cat tmp.out` )
I then run this through a for loop like so
for i in ${ARRAY[#]};do echo ${i}; done
But the output ends up like this:
c:\My
files\testing\more
files\stuff\test.sas
c:\testing\files
here\less
files\less
stuff\mytest.sas
and I want the output to be:
c:\My files\testing\more files\stuff\test.exe
c:\testing\files here\less files\less stuff\mytest.exe
How can I resolve this?
In order to iterate over the values in an array, you need to quote the array expansion to avoid word splitting:
for i in "${values[#]}"; do
Of course, you should also quote the use of the value:
echo "${i}"
done
That doesn't answer the question of how to get the lines of a file into an array in the first place. If you have bash 4.0, you can use the mapfile builtin:
mapfile -t values < tmp.out
Otherwise, you'd need to temporarily change the value of IFS to a single newline, or use a loop over the read builtin.
You can use the IFS variable, the Internal Field Separator. Set it to empty string to split the contents on newlines only:
while IFS= read -r line ; do
ARRAY+=("$line")
done < tmp.out
-r is needed to keep the literal backslashes.
Another simple way to control word-splitting is by controlling the Internal Field Separator (IFS):
#!/bin/bash
oifs="$IFS" ## save original IFS
IFS=$'\n' ## set IFS to break on newline
array=( $( <dat/2lines.txt ) ) ## read lines into array
IFS="$oifs" ## restore original IFS
for ((i = 0; i < ${#array[#]}; i++)) do
printf "array[$i] : '%s'\n" "${array[i]}"
done
Input
$ cat dat/2lines.txt
c:\My files\testing\more files\stuff\test.exe
c:\testing\files here\less files\less stuff\mytest.exe
Output
$ bash arrayss.sh
array[0] : 'c:\My files\testing\more files\stuff\test.exe'
array[1] : 'c:\testing\files here\less files\less stuff\mytest.exe'

Error in reading a multi-line string into an array?

I am using the following bash codes to want to read a multi-line string into an array. I want each array element corresponds to one line of the string.
mytext="line one
line two
line three"
IFS=$'\n' read -a lines <<<"${mytext}"
echo "len=${#lines[#]}"
for line in "${lines[#]}"
do
echo "[$line]"
done
I expect "len" should be equal to 3 and the "lines" array should be properly initialized. However, I got the following result :
len=1
[line one]
Have I used the wrong "IFS" ? What are the mistakes in the bash codes ?
Thanks in advance.
What's wrong with your solution is that read always reads a single line at a time, so telling it the IFS is a newline will make it read the entire line into the first element of the array. Each time you read you'll still overwrite the entire array. You can either build up the array iteratively:
lines=()
while read; do
lines+=("$REPLY")
done <<< "$mytext"
or by swapping the newlines for something else:
IFS='+' read -a lines <<< "${mytext//$'\n'/+}"
$ IFS=#
$ echo "${lines[*]}"
line one#line two#line three
Using mapfile (a.k.a. readarray) would be a more coherent, elegant solution, but that's only supported in Bash 4:
mapfile -t lines <<< "$mytext"
$ printf '[%s]\n' "${lines[#]}"
[line one]
[line two]
[line three]
Without the -t flag, mapfile will keep the newline attached to the array element.
This while loop should work:
arr=()
while read -r line; do
arr+=("$line")
done <<< "$mytext"
set | grep arr
arr=([0]="line one" [1]="line two" [2]="line three")
Not sure what is wrong in your case, but here is a workaround:
a=0
while read lines[$a]; do
((a++))
done <<< "${mytext}"
unset lines[$a]; #last iteration has already failed. Unset that index.

How to split a multi-line string containing the characters "\n" into an array of strings in bash? [duplicate]

This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 6 years ago.
I have a string in the following format:
I'm\nNed\nNederlander
I'm\nLucky\nDay
I'm\nDusty\nBottoms
I would like to move this to an array of strings line by line such that:
$ echo "${ARRAY[0]}"
I'm\nNed\nNederlander
$ echo "${ARRAY[1]}"
I'm\nLucky\nDay
$ echo "${ARRAY[2]}"
I'm\nDusty\nBottoms
However, I'm running into problems with the "\n" characters within the string itself. They are represented in the string as two separate characters, the backslash and the 'n', but when I try to do the array split they get interpreted as newlines. Thus typical string splitting with IFS does not work.
For example:
$ read -a ARRAY <<< "$STRING"
$ echo "${#ARRAY[#]}" # print number of elements
2
$ echo "${ARRAY[0]}"
I'mnNednNederla
$ echo "${ARRAY[1]}"
der
By default, the read builtin allows \ to escape characters. To turn off this behavior, use the -r option. It is not often you will find a case where you do not want to use -r.
string="I'm\nNed\nNederlander
I'm\nLucky\nDay
I'm\nDusty\nBottoms"
arr=()
while read -r line; do
arr+=("$line")
done <<< "$string"
In order to do this in one-line (like you were attempting with read -a), actually requires mapfile in bash v4 or higher:
mapfile -t arr <<< "$string"
mapfile is more elegant, but it is possible to do this in one (ugly) line with read (useful if you're using a version of bash older than 4):
IFS=$'\n' read -d '' -r -a arr <<< "$string"

Resources