Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to accomplish the equivalent of:

list=()
while read i; do
  list+=("$i")
done <<<"$input"

with

IFS=$'\n' read -r -a list <<<"$input"

What am I doing wrong?

input=`/bin/ls /`

IFS=$'\n' read -r -a list <<<"$input"

for i in "${list[@]}"; do
  echo "$i"
done

This should print a listing of /, but I'm only getting the first item.

share|improve this question
4  
If you are really trying to parse the output of ls, don't. Use list=(/*). – chepner Nov 23 '15 at 14:50

You must use mapfile (or its synonym readarray, which was introduced in bash 4.0):

mapfile -t list <<<"$input"

One read invocation only work with one line, not the entire standard input.

read -a list populate the content of first line of standard in to the array list. In your case, you got bin as the only element in array `list.

share|improve this answer
    
For anyone working with older versions of Bash, this feature was introduced with Version 4. – Anthony Geoghegan Nov 23 '15 at 12:43
1  
@AnthonyGeoghegan: Forgot to mention it, added! – cuonglm Nov 23 '15 at 12:49
2  
@cuonglm The IFS is useless, because mapfile doesn't do any word-splitting on its input. – chepner Nov 23 '15 at 14:47
    
@StéphaneChazelas: My bad, removed it. – cuonglm Nov 23 '15 at 15:34
    
@chepner: Thanks, I removed it. – cuonglm Nov 23 '15 at 15:37

for bash versions that do not support mapfile

IFS=$'\n' read -ra list -d '' <<< "$input"

should do the trick

share|improve this answer
2  
One minor drawback; this command will always have a non-zero exit status. – chepner Nov 23 '15 at 14:46
2  
Also note that it removes empty elements. – Stéphane Chazelas Nov 23 '15 at 16:47

Solution for Bash version 3 (and 4)

I happened to be logged in to a CentOS 5 box running Bash 3 and I had been working on a solution. I’ve already upvoted cuonglm’s answer but I thought I may as well post the solution I came up with that should work with Bash 3 (and 4). I’ve tested it with a file which had a space in its name and another which begins with -.

Instead of

IFS=$'\n' read -r -a list <<<"$input"

simply use command substitution to create and populate the array:

IFS=$'\n' # split on newline only
set -f    # disable globbing
list=($(printf "%s" "$input"))

Note: This won’t work with filenames which have newlines in their name.

share|improve this answer
    
@StéphaneChazelas Thanks for the edit (adding set -f). I was assuming that since the OP was setting the contents of input to the output of /bin/ls that it wouldn't contain glob patterns -- but that isn't necessarily the case. – Anthony Geoghegan Nov 23 '15 at 16:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.