Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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
3  
If you are really trying to parse the output of ls, don't. Use list=(/*). – chepner 17 hours ago

3 Answers 3

up vote 3 down vote accepted

for bash versions that do not support mapfile

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

should do the trick

share|improve this answer
    
One minor drawback; this command will always have a non-zero exit status. – chepner 17 hours ago
    
Also note that it removes empty elements. – Stéphane Chazelas 15 hours ago

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 19 hours ago
1  
@AnthonyGeoghegan: Forgot to mention it, added! – cuonglm 19 hours ago
2  
@cuonglm The IFS is useless, because mapfile doesn't do any word-splitting on its input. – chepner 17 hours ago
    
@StéphaneChazelas: My bad, removed it. – cuonglm 16 hours ago
    
@chepner: Thanks, I removed it. – cuonglm 16 hours ago

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
    
If there are any problems with this solution, I'd appreciate the feedback. PSkocik previously answered a few of my questions so I figured I should reciprocate. – Anthony Geoghegan 18 hours ago
    
@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 14 hours ago

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.