Replace space between filepaths with newline

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?

Asked By: laconbass

||

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

Answered By: laconbass

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.

Answered By: unxnut

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.

Answered By: Joseph R.

In this case I would use printf:

printf '%sn' /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 '%sn' /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.

Answered By: evilsoup

Be pragmatic, use GNU sed!!

    sed -i 's/s+/n/g' file

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

The -i parameter stands for changing the file "in place".

This is more or less "substitute /one space or more/ for /newline/ globally".

Answered By: MGP

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 does not 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 '%sn' "$@"

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 is 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 …

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

cat filename | tr ' ' 'n' | tee filename
Answered By: sanjeev kanabargi

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.

Answered By: FranMowinckel
echo word1 word2 ... | sed -e 'y/ /n/;P;D'

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

Answered By: user218374

Here an example

list=$(cat index.txt | grep href=)
for iterator in $list
do
       echo $iterator
done

Here I have string with many links and space between every link, when you use loops it will solve your problem

Answered By: Abdelrahman Saleh

The question on the title: replace space with new line

The simple, quick, brute force solution is to do exactly that, replace all spaces with new lines:

echo "$input" | tr ' ' 'n'
echo "$input" | sed 'y/ /n/'
echo "$input" | sed 's/ /n/g'

Filenames

But in your question you are listing a list of paths:

echo '/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5' > test.txt

Using the solution above will not work for filenames with spaces (or newlines).

Better

But we can use a two characters delimiter: / (space slash)
That pair of characters could only exist at the beginning of a new (absolute) path:

input='/path/to/file /path/to/file2 /path/to/one space /path/to/new
line /path/to/file5'

$ printf '%sn' "$input" | sed 's# /#n/#g'

/path/to/file
/path/to/file2
/path/to/one space
/path/to/new
line
/path/to/file5

For relative paths, we need to also allow paths that start with ./ or ../:

$ cat test2.txt 
/path/to/file /path/to/file2 /path/to/one space /path/to/new
line /path/to/file5 ./path/to/file ../path/to/file2 ./path/to/one space ./path/to/new
line ./path/to/file5 ../path/to/file ../path/to/file2 ../path/to/one space ../path/to/new
line ../path/to/file5


$ sed 's# ([.]{0,2}/)#n1#g' test2.txt 
/path/to/file
/path/to/file2
/path/to/one space
/path/to/new
line
/path/to/file5
./path/to/file
../path/to/file2
./path/to/one space
./path/to/new
line
./path/to/file5
../path/to/file
../path/to/file2
../path/to/one space
../path/to/new
line
../path/to/file5

Best

For path names with newlines it is better to quote each pathname.

$ sed -e '1s/^/"/' -e 's# ([.]{0,2}/)#"n"1#g' -e '$s/$/"/' test2.txt

"/path/to/file"
"/path/to/file2"
"/path/to/one space"
"/path/to/new
line"
"/path/to/file5"
"./path/to/file"
"../path/to/file2"
"./path/to/one space"
"./path/to/new
line"
"./path/to/file5"
"../path/to/file"
"../path/to/file2"
"../path/to/one space"
"../path/to/new
line"
"../path/to/file5"

Answered By: user232326

option1:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"|perl -pne  "s/ /n/g"

option2:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"|awk '{gsub(/ /,"n",$0);print }'```

output

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



Answered By: Praveen Kumar BS

Using Raku (formerly known as Perl_6)

Sample Input:

/path/to/file1 /path/to/file2 /path/to/file3

Split on whitespace (before forwardslash):

~$ raku -ne '.put for .split(/ s <?before "/">/);'  file

Sample Output:

/path/to/file1
/path/to/file2
/path/to/file3

This is just to get you started. What’s nice is that if you just add .IO to the code above, Raku’s object system from this point will recognize IO::Path objects, including the correct path separator (backslash for Windows). The objective is to make your code more portable from platform to platform. Below results from adding .IO and change the put call to say:

~$ raku -ne '.IO.say for .split(/ s <?before "/">/);'  file 
"/path/to/file".IO
"/path/to/file2".IO
"/path/to/file3".IO

Reading your file containing the list of files, and extracting the filenames, a.k.a. basename:

~$ raku -ne '.IO.say for .split(/ s <?before "/">/);'  file 
file1
file2
file3

Finally, you can output the contents of the first file, by slurping in the [0]th element. Assuming these are relative paths, from the directory you’re in on the command line you use ~ tilde to concatenate the path either with a leading . dot, or with $*CWD:

raku -ne '.map($*CWD ~ *).IO.slurp.put for .split(/ s <?before "/">/)[0];'
#returns output of first file in list (assumes relative paths)

https://docs.raku.org/type/IO::Path
https://raku.org

Answered By: jubilatious1
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.