How can I assign a value to an array in Bash? - arrays

I am trying to read a list of values from a text file, hello.txt, and store them in an array.
counter=0
cat hello.txt | while read line; do
${Unix_Array[${counter}]}=$line;
let counter=counter+1;
echo $counter;
done
echo ${Unix_Array[0]}
echo ${Unix_Array[1]}
echo ${Unix_Array[2]}
I am not able to assign values to the array Unix_Array[]... The echo statement does not print the contents of the array.

There are a few syntax errors here, but the clear problem is that the assignments are happening, but you're in an implied subshell. By using a pipe, you've created a subshell for the entire while statement. When the while statement is done, the subshell exits and your Unix_Array ceases to exist.
In this case, the simplest fix is not to use a pipe:
counter=0
while read line; do
Unix_Array[$counter]=$line;
let counter=counter+1;
echo $counter;
done < hello.txt
echo ${Unix_Array[0]}
echo ${Unix_Array[1]}
echo ${Unix_Array[2]}
By the way, you don't really need the counter. An easier way to write this might be:
$ oIFS="$IFS" # Save the old input field separator
$ IFS=$'\n' # Set the IFS to a newline
$ some_array=($(<hello.txt)) # Splitting on newlines, assign the entire file to an array
$ echo "${some_array[2]}" # Get the third element of the array
c
$ echo "${#some_array[#]}" # Get the length of the array
4

If you are using Bash v4 or higher, you can use mapfile to accomplish this:
mapfile -t Unix_Array < hello.txt
Otherwise, this should work:
while read -r line; do
Unix_Array+=("$line")
done < hello.txt

The best way I found is:
declare -a JUPYTER_VENV
JUPYTER_VENV+=( "test1" "test2" "test3" )
And then consume it with:
for jupenv in "${JUPYTER_ENV[#]}"
do
echo "$jupenv"
done

Instead of this:
cat hello.txt | while read line; do
${Unix_Array[${counter}]}=$line;
let counter=counter+1;
echo $counter;
done
You can just do this:
Unix_Array=( `cat "hello.txt" `)

It’s a solution:
count=0
Unix_Array=($(cat hello.txt))
array_size=$(cat hello.txt | wc -l)
for ((count=0; count < array_size; count++))
do
echo ${Unix_Array[$count]}
done

Related

bash create for loop with an array variable

i am trying to make output of a command be read by a for loop, but in such a way that the loop variable would be an array. is that possible?
this is what I've been trying so far:
function samplevals() {
echo '"aa bb"'
echo '"cc dd"'
echo '"ee ff" "gg hh"'
}
samplevar='"aa bb"
"cc dd"
"ee ff" "gg hh"'
echo call function samplevals:
for x in `samplevals `; do echo ">$x<"; done
echo read variable samplevar:
echo $samplevar
for x in $samplevar; do echo ">$x<"; done
echo process output of 'echo samplevar:'
for x in `echo $samplevar`; do echo ">$x<"; done
echo "the thing with set"
for x in $samplevar; do set -- $x ; echo "\$1=>$1<,\$2=>$2<"; done
but the output is always the same:
>"aa<
>bb"<
>"cc<
>dd"<
>"ee<
>ff"<
>"gg<
>hh"<
Can I somehow prevent bash from splitting the elements into smaller pieces?
Along the lines of chepner's answer, using read command. The -a flag part of the command lets the output to written out to an array.
IFS=$'\t' read -ra arrayDef < <(echo -ne '"abc def"\t"ghi jkl"')
for x in "${arrayDef[#]}"; do
echo ">$x<"
done
You can replace the echo part with some command that generates such a string. Remember to update the IFS appropriately as to how the string is de-limited. In my case, I just a have the string de-limited by \t
The way to define an array in bash is
samplevars=("aa bb" "cc dd" "ee ff" "gg hh")
for x in "${samplevars[#]}"; do
echo ">$x<"
done

Read a file and affect the splitting result in an array with bash

My code read a file by line and split each line by a comma ; or space and the results is affected to an array, but the proble is that i can't read the elmen of the array
#!/bin/bash
filename="$1"
while read -r line
do
name=$line
echo "Name read from file - $name"
arr=$(echo $name | tr ";" "\n")
echo ${arr[1]}
for x in $arr
do
echo "> [$x]"
var1=$x
var2=$x
done
done < "$filename"
the problem is in the command:
echo ${arr[1]}
the file that i use contain line :
car; vehicle
computer;apple
To loop through an array:
for x in "${arr[#]}"; do
echo "> [$x]"
done
The ${arr[#]} expansion will include the entire array, while $arr alone only includes the first array element.
However if you use read -ra with custom IFS then you can directly read each delimited line into an array:
while IFS=';' read -ra arr; do
printf "[%s]\n" "${arr[#]}"
echo '----------'
done < file
Output:
[car]
[vehicle]
----------
[computer]
[apple]
----------

Bash script array to csv

I want to do comma separated string from my array. In my script i collecting data to array outputArr and then i want to echo it to check it out, but now i'm stuck. I want to print it on console using:
echo ${outputArr[*]}
But i'm getting wrong output. So i'm trying to debug it and write it like this:
echo ${outputArr[0]}
echo ${outputArr[1]}
echo ${outputArr[*]}
echo "-------------"
OK here is my output:
Terminally Yours
2204
2204nally Yours
-------------
and other example:
Alfa
1491
1491
-------------
Why this is overwritten with space in the beginning? Of course my goal is (finally):
Alfa;1491
In this point:
Alfa1491
EDIT:
while read -r line
do
singleLine=$line
if [[ $singleLine =~ $regexVenueName ]]
then
singleLine=${singleLine/<span id=\"ctl00_MainContent_lbPartner\" class=\"Partner\">/}
singleLine=${singleLine/<\/span> <br \/><br \/>/}
partnerVenueNameOutput+="$singleLine"
outputArr[0]=$singleLine
fi
done < "$f"
Your array contains elements with carriage returns:
$ foo=($'\rterminally yours' $'\r2204')
$ echo "${foo[0]}"
terminally yours
$ echo "${foo[1]}"
2204
$ echo "${foo[*]}"
2204inally yours
For your code, you can add the following to remove the carriage return from the variable:
singleLine=${singleLine//$'\r'/}
To remove any trailing carriage returns from each array element, try
outputArray=( "${outputArray[#]%$'\r'}" )
However, it would probably be better to examine how outputArray is set in the first place and prevent the carriage returns from being added in the first place. If you are reading from a file that uses DOS line endings, try "cleaning" it first using dos2unix.

populate and read an array with a list of filenames

Trivial question.
#!/bin/bash
if test -z "$1"
then
echo "No args!"
exit
fi
for newname in $(cat $1); do
echo $newname
done
I want to replace that echo inside the loop with array population code.
Then, after the loop ends, I want to read the array again and echo the contents.
Thanks.
If the file, as your code shows, has a set of files, each in one line, you can assign the value to the array as follows:
array=(`cat $1`)
After that, to process every element you can do something like:
for i in ${array[#]} ; do echo "file = $i" ; done
declare -a files
while IFS= read -r
do
files+=("$REPLY") # Array append
done < "$1"
echo "${files[*]}" # Print entire array separated by spaces
cat is not needed for this.
#!/bin/bash
files=( )
for f in $(cat $1); do
files[${#files[*]}]=$f
done
for f in ${files[#]}; do
echo "file = $f"
done

how do I output the contents of a while read line loop to multiple arrays in bash?

I read the files of a directory and put each file name into an array (SEARCH)
Then I use a loop to go through each file name in the array (SEARCH) and open them up with a while read line loop and read each line into another array (filecount). My problem is its one huge array with 39 lines (each file has 13 lines) and I need it to be 3 seperate arrays, where
filecount1[line1] is the first line from the 1st file and so on. here is my code so far...
typeset -A files
for file in ${SEARCH[#]}; do
while read line; do
files["$file"]+="$line"
done < "$file"
done
So, Thanks Ivan for this example! However I'm not sure I follow how this puts it into a seperate array because with this example wouldnt all the arrays still be named "files"?
If you're just trying to store the file contents into an array:
declare -A contents
for file in "${!SEARCH[#]}"; do
contents["$file"]=$(< $file)
done
If you want to store the individual lines in a array, you can create a pseudo-multi-dimensional array:
declare -A contents
for file in "${!SEARCH[#]}"; do
NR=1
while read -r line; do
contents["$file,$NR"]=$line
(( NR++ ))
done < "$file"
done
for key in "${!contents[#]}"; do
printf "%s\t%s\n" "$key" "${contents["$key"]}"
done
line 6 is
$filecount[$linenum]}="$line"
Seems it is missing a {, right after the $.
Should be:
${filecount[$linenum]}="$line"
If the above is true, then it is trying to run the output as a command.
Line 6 is (after "fixing" it above):
${filecount[$linenum]}="$line"
However ${filecount[$linenum]} is a value and you can't have an assignment on a value.
Should be:
filecount[$linenum]="$line"
Now I'm confused, as in whether the { is actually missing, or } is the actual typo :S :P
btw, bash supports this syntax too
filecount=$((filecount++)) # no need for $ inside ((..)) and use of increment operator ++
This should work:
typeset -A files
for file in ${SEARCH[#]}; do # foreach file
while read line; do # read each line
files["$file"]+="$line" # and place it in a new array
done < "$file" # reading each line from the current file
done
a small test shows it works
# set up
mkdir -p /tmp/test && cd $_
echo "abc" > a
echo "foo" > b
echo "bar" > c
# read files into arrays
typeset -A files
for file in *; do
while read line; do
files["$file"]+="$line"
done < "$file"
done
# print arrays
for file in *; do
echo ${files["$file"]}
done
# same as:
echo ${files[a]} # prints: abc
echo ${files[b]} # prints: foo
echo ${files[c]} # prints: bar

Resources