65

How can I replace spaces with new lines on an input like:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 etc...

To obtain the following:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

Note

I'm posting this question to help other users, it was not easy to find a useful answer on UNIX SE until I started to type this question. After that I found the following:

Related question

How can I find and replace with a new line?

114

Use the tr command

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"\
| tr " " "\n"

Found on http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html

  • tr was my first thought as well, although there are so many ways to do it! This is pretty much EXACTLY what tr is for, though! – Rob Dec 17 '13 at 15:43
  • 5
    +1, but as a comment: That does not work if the filenames contain spaces themselves – Bonsi Scott Dec 17 '13 at 16:10
20

In this case I would use printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

If there are spaces within the one of the paths, you can quote that filepath in order to prevent it from being split on the spaces:

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

To transform text in general, tr is your best bet, as covered in an existing answer.

  • 1
    A quick note from the future: thanks for posting this solution, it's been very reliable for me, compared to using "echo". – Liesmith Apr 30 '15 at 21:48
5

Assuming you have a string with spaces as separators:

newline_separated=${space_separated// /$'\n'}

However you're probably asking the wrong question. (Not necessarily, for example this might come up in a makefile.) A space-separated list of file names doesn't really work: what if one of the file names contained spaces?

If a program receives file names as arguments, don't join them with spaces. Use "$@" to access them one by one. Although echo "$@" prints the arguments with spaces in between, that's due to echo: it prints its arguments with spaces as separators. somecommand "$@" passes the file names as separate arguments to the command. If you want to print the arguments on separate lines, you can use

printf '%s\n' "$@"

If you do have space-separated file names and you want to put them in an array to work on them, you can use an unquoted variable expansion to split the value at characters on IFS (you'll need to disable wildcard expansion with set -f, otherwise glob patterns will be expanded in the value):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do …

You can encapsulate this in a function that restores the -f setting and the value of IFS when it's done:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do …
  • Changing the correct answer to this one. I think it's more correct to research how I got to a space-separated list, and retrieve that information in another way. It would be cool for learners like me if you comment a bit your snipnet, telling us what do things like the local var IFS or the condition $- = f do. That kind of things a person that uses bash few times don't knows. – laconbass Dec 11 '14 at 22:01
  • @laconbass I've added a short explanation. Look up set -f and IFS in the bash manual if you want all the details. See also unix.stackexchange.com/questions/16192/… – Gilles Dec 11 '14 at 22:26
  • @Guilles That short explanation is enough for me, and i think it will be for many others. Ty for your time – laconbass Dec 12 '14 at 2:31
  • setting IFS locally does not take effect – Eliran Malka Apr 20 '17 at 23:35
  • @EliranMalka I have no idea what you mean by this. If a script doesn't behave the way you think it should, you can ask a question here. – Gilles Apr 21 '17 at 8:32
4

Be pragmatic, use sed!!

sed 's/\s\+/\n/g' file

The above says to substitute one or more whitespace characters (\s+) with newline (\n)

This is more or less:

'substitute /one space or more/ for /newline/ globally'
  • 1
    replace change with substitute, that's what the s actually stands for! – Rob Dec 17 '13 at 16:37
  • @Rob thanks, remember you can edit others answers. – MGP Dec 17 '13 at 16:42
  • 1
    If you have multiple spaces between text then you will get blank lines. You need to add a '+' after the \s to indicate that you want to match at least one spaces as apposed to exactly one space. ie. sed 's/\s+/\n/g' – DarkHeart Dec 17 '13 at 20:43
4

As an alternative to tr from @laconbass, you can also use xargs in this case:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

The advantage is that it works even with multiple whitespaces, which tr doesn't.

0

Here is how I did it:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

Notice the use of Enter key after backslash in the sed command.

  • what prons and cons has sed over tr? – laconbass Dec 17 '13 at 15:33
  • Your comfort level :-) I think you can do more with sed as it is an editor rather than simply translate characters. – unxnut Dec 17 '13 at 15:38
  • 4
    sed can do so much more, but is totally overkill for this. tr is the right tool for THIS job, but knowledge of sed and regexes will certainly come in handy later! – Rob Dec 17 '13 at 15:44
0

Another approach, assuming the line is in a variable called line:

for path in $line;do echo $path;done

This makes use of the fact that Bash splits its arguments on whitespace by default and that echo appends a newline to its input by default.

  • I tried this on my ubuntu system before i posted this question and couldn't get it to work. – laconbass Dec 17 '13 at 16:38
0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

is another method to turn single-space-separated words into newline separated.

-3

The following script is easy to understand and easy to use.

cat filename | tr ' ' '\n' | tee filename
  • 2
    The essence of your answer (tr) is the same as in the accepted answer. Beside that your answer has following issues: a) the command is not indented with 4 spaces (-> markdown layout) b) Your use of cat is useless (you can replace it with < filename tr ' ' '\n'). c) Your output filename is the same as the input filename. With that you create a data race. – maxschlepzig Sep 3 '15 at 6:26
  • 1
    apart from maxschlepzig's correct analysis, this is not a script, but a bunch of connected commands that have a name hardcoded (as script would hopefully have a header specifying the shell to use and use two parameters to specify in and output). Apart from that 2 out of 3 people in my household do not find it easy to understand. Maybe that is is not representative, but keep in mind that something you yourself understand (or in this case think you understand) always seems easy. – Anthon Sep 3 '15 at 6:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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