1

I'm trying to split a string into an array using a delimiter other than space, keeping spaces preserved.

For example, if I run:

files=$(echo "foo.txt:bar.txt:my story.txt" | tr ":" "\n")
for f in $files; do
    echo $f
done

I get:

foo.txt
bar.txt
my
story.txt

How can I preserve the spaces?

3
  • I believe that the spaces are preserved in the above code. Test it again. Commented Jan 4, 2018 at 23:04
  • @VenkateshMarepalli It split my story.txt into my and story.txt Commented Jan 4, 2018 at 23:07
  • @VenkateshMarepalli, why would you expect spaces to be preserved? The unquoted expansion is subject to string splitting. See the output from ideone's online interpreter at ideone.com/kTj9A7 Commented Jan 4, 2018 at 23:10

2 Answers 2

7

files=$(cmd) is not an array assignment. It's a string assignment (the output of cmd is assigned to a regular variable files).

I would recommend using read -a to split the string as globs won't be an issue:

IFS=: read -ra files <<< "foo.txt:bar.txt:my story.txt"

for f in "${files[@]}"; do
    echo "$f"
done
Sign up to request clarification or add additional context in comments.

Comments

2

Use IFS to specify the field separator:

IFS=: files=($(echo "foo.txt:bar.txt:my story.txt"))
for f in "${files[@]}"; do
    echo "$f"
done

You also need to put parentheses around the value to make an array. You just set $files to a string where the : were replaced with newline. When you then expand $files, word splitting uses any form of whitespace, so spaces and newlines are field separators.

3 Comments

Need to disable globbing for this to be safe.
Also note that IFS will be changed.
It will not be changed. It's specified as a variable only for a specific command execution. You can try it out: IFS=: files=($(echo "foo.txt:bar.txt:my story.txt")); echo ${IFS}; echo ${files[2]} To me this is a very good answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.