4

I'm trying to use an array with while read, but the entire array is output at once.

#!/bin/bash

declare -a arr=('1:one' '2:two' '3:three');

while read -e it ; do
    echo $it
done <<< ${arr[@]}

It should output each value separately (but doesn't), so maybe while read isn't the hot ticket here?

2
  • 1
    cat <<< ${arr[@]} puts all elements on the same line. Commented May 28, 2016 at 21:46
  • @couling: I tried < and << also, but didn't really get it. Commented May 28, 2016 at 21:51

3 Answers 3

11

For this case, it is easier to use a for loop:

$ declare -a arr=('1:one' '2:two' '3:three')
$ for it in "${arr[@]}"; do echo $it; done
1:one
2:two
3:three

The while read approach is very useful (a) When you want to read data from a file, and (b) when you want to read in a nul or newline separated string. In your case, however, you already have the data in a bash variable and the for loop is simpler.

Sign up to request clarification or add additional context in comments.

5 Comments

Is it not possible for a while loop to read arrays, or can I add a newline string to the array so it takes the behavior of reading a file? just curious about that really... thanks!
@CocoaPuffs -- you would probably need a second while loop to echo (write) out the data so you can read it -- so not a good solution to try to use a while loop
@CocoaPuffs The array is already a bash variable. Using while read would mean taking it out of the bash variable as a string which read would then reprocess into new bash variables. I'm sure that there are cases where that is useful but they would be quite rare.
@CocoaPuffs if you REALLY want to do that you can use the -d flag with read to set the delimeter. But this is NOT recomended. ss64.com/bash/read.html
That's what I figured, but wanted to ask about it anyway (in the event there is that rare situation). Thank all of you (@John1024, @Soren, @couling)!
2

possible by while loop

#!/bin/bash

declare -a arr=('1:one' '2:two' '3:three');
len=${#arr[@]}
i=0
while [ $i -lt $len ]; do
    echo "${arr[$i]}"
    let i++
done

Comments

1

With the Bash script below you should achieve what you want.

#!/bin/bash

# Ensure fail-fast script execution.
shopt -os nounset pipefail errexit errtrace

declare -a arr=('1:one' '2:two' '3:three');

while read -r it; do
    echo "${it}"
done < <(printf '%s\n' "${arr[@]}")

A couple of things to note here:

  1. In general you should be making all your scripts fail-fast by setting the appropriate shell options with shopt -os.
  2. Readline is not needed to read each line (array element) into the variable it because you're not interacting with the terminal while the script is running.
  3. Instead it is usually good to prevent the interpretation of any backslash-escaped characters by passing read its -r option.
  4. You should always surround variable references by double-quotes and place the variable names inside a pair of curly braces. Quoting prevents all kinds of errors if a variable is expanded and its value contains whitespace. Curly braces on the other hand foster readability by setting the variable name apart from the dollar sign (and surrounding text when expanded into an interpolated string).
  5. The printf '%s\n' statement prints each array element on a new line. The output printf produces is then directly fed via the standard input stream into the while loop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.