1703

How can I replace a newline ("\n") with a space ("") using the sed command?

I unsuccessfully tried:

sed 's#\n# #g' file
sed 's#^$# #g' file

How do I fix it?

Flimm
  • 136,138
  • 45
  • 251
  • 267
hhh
  • 50,788
  • 62
  • 179
  • 282
  • 46
    `tr` is only the right tool for the job if replace a single character for a single character, while the example above shows replace newline with a space.. So in the above example, tr could work.. But would be limiting later on. – Angry 84 Dec 31 '15 at 02:47
  • @Mayhem, `sed 's/$/ NewDelim/' | tr '\n' ' '`. Use `sed` to append the new delimiter to the end of each line, then remove newlines with `tr`. Less cryptic than the `sed` only way, IMO. – cp.engr Jan 19 '16 at 19:08
  • 16
    `tr` in the right tool for the job because the questioner wanted to replace each newline with a space, as shown in his example. The replacement of newlines is uniquely arcane for `sed` but easily done by `tr`. This is a common question. Performing regex replacements is not done by `tr` but by `sed`, which would be the right tool... for a different question. – Mike S Dec 28 '16 at 15:01
  • 3
    "tr" can also just delete the newline ` tr -d '\n' ` however you may also like to delete returns to be more universal ` tr -d '\012\015' `. – anthony Feb 27 '17 at 23:44
  • 4
    WARNING: "tr" acts differently with regards to a character ranges between Linux and older Solaris machines (EG sol5.8). EG: ` tr -d 'a-z' ` and ` tr -d '[a-z]' `. For that I recommend you use "sed" which doesn't have that difference. – anthony Feb 27 '17 at 23:45
  • 2
    @MikeS Thanks for the answer. Follow `tr '\012' ' '` with an `echo`. Otherwise the last linefeed in the file is deleted, too. `tr '\012' ' ' < filename; echo`does the trick. – Bernie Reiter Dec 28 '17 at 23:30
  • 1
    @BernieReiter One can neatly mitigate the final newline removal issue by calling the `tr` command in an `echo` command subshell: `echo $(tr "\012" " ")`. – Patrick Dark Mar 26 '19 at 18:15
  • @Patrick Dark `cat text.txt | echo $(tr "\012" " ")` Cool :-) Thanks for the tip! – Bernie Reiter Mar 28 '19 at 11:46
  • `tr` is not useful if you want to replace some newlines, dependent on whether they have other characters next to them or not. Here is a good `sed` answer simpler than all listed below: https://stackoverflow.com/a/12129896/134044 – NeilG Feb 16 '20 at 23:47
  • @MikeS This is just a toy example though, and the questioner specifically asked for how to do it with `sed` – Sam May 22 '20 at 19:54
  • `perl -0777 -p -e 's/\n/ /' file` – caw Sep 20 '21 at 03:01
  • See also [sed substitute variable contains newline (preserve it)](/questions/28664782/sed-substitute-variable-contains-newline-preserve-it) – tripleee Nov 03 '21 at 06:50

43 Answers43

2003

sed is intended to be used on line-based input. Although it can do what you need.


A better option here is to use the tr command as follows:

tr '\n' ' ' < input_filename

or remove the newline characters entirely:

tr -d '\n' < input.txt > output.txt

or if you have the GNU version (with its long options)

tr --delete '\n' < input.txt > output.txt
Ayman Salah
  • 1,039
  • 14
  • 35
dmckee --- ex-moderator kitten
  • 98,632
  • 24
  • 142
  • 234
  • I cannot understand why sed cannot do it. Please, clarify to use different tool. – Léo Léopold Hertz 준영 Aug 09 '09 at 19:18
  • 117
    Sed is line-based therefore it is hard for it to grasp newlines. – Alexander Gladysh Aug 09 '09 at 19:22
  • 3
    Alexander: Does "stream editor" mean line-based? Perhaps, the name is confusing. – Léo Léopold Hertz 준영 Aug 09 '09 at 19:26
  • 224
    sed works on a "stream" of input, but it comprehends it in newline delimited chunks. It is a unix tool, which means it does one thing very well. The one thing is "work on a file line-wise". Making it do something else will be hard, and risks being buggy. The moral of the story is: choose the right tool. A great many of your questions seem to take the form "How can I make this tool do something it was never meant to do?" Those questions are interesting, but if they come up in the course of solving a real problem, you're probably doing it wrong. – dmckee --- ex-moderator kitten Aug 09 '09 at 19:39
  • sed isn't self-explanatory, but how th replace end of lines at specific locations only ? – user1767316 Oct 22 '20 at 15:30
  • 1
    `GNU sed` supports changing the "record" separator to null byte instead of newline. – Jacek Krysztofik Jan 06 '21 at 02:37
  • How do you prevent replacing the final newline? – dalanmiller Jul 08 '21 at 02:18
  • 4
    `tr` only works with one character strings. You can't replace all new lines with a string that is multiple characters long. – Flimm Jan 06 '22 at 13:45
1779

Use this solution with GNU sed:

sed ':a;N;$!ba;s/\n/ /g' file

This will read the whole file in a loop (':a;N;$!ba), then replaces the newline(s) with a space (s/\n/ /g). Additional substitutions can be simply appended if needed.

Explanation:

  1. sed starts by reading the first line excluding the newline into the pattern space.
  2. Create a label via :a.
  3. Append a newline and next line to the pattern space via N.
  4. If we are before the last line, branch to the created label $!ba ($! means not to do it on the last line. This is necessary to avoid executing N again, which would terminate the script if there is no more input!).
  5. Finally the substitution replaces every newline with a space on the pattern space (which is the whole file).

Here is cross-platform compatible syntax which works with BSD and OS X's sed (as per @Benjie comment):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

As you can see, using sed for this otherwise simple problem is problematic. For a simpler and adequate solution see this answer.

coldfix
  • 6,604
  • 3
  • 40
  • 50
Zsolt Botykai
  • 50,406
  • 14
  • 85
  • 110
  • 133
    You can run this cross-platform (i.e. on Mac OS X) by separately executing the commands rather than separating with semi-colons: `sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'` – Benjie Sep 27 '11 at 11:16
  • 4
    It seems not to remove the last \n ? – Pierre-Gilles Levallois Aug 04 '20 at 10:55
  • See number 3 above. It seems that $! means not to do it on the last line as there should be one final newline. – gaoagong Mar 01 '21 at 18:45
  • 4
    This is an impressive answer. I also find it ironic that Linux tools are supposed to be "do one thing well" when it seems like most Linux tools do many things, poorly – Andy Ray May 20 '21 at 22:24
  • 4
    `echo "Hello\nWorld" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'` returns "Hello World", but `echo "Hello World" | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'` returns an empty string for me. I'm on MacOS Big Sur. – Tobias Bergkvist May 25 '21 at 17:15
  • Your description of the N command is somewhat confusing: When the cycle starts (we have just one cycle here), sed reads the first line of input, removes any trailing \n and places it in the pattern space, then it processes the script. N adds a newline to the pattern space, then appends the next line of input (without trailing \n) to the pattern space. – Christoph Jul 11 '21 at 18:26
  • 1
    @AndyRay: Really? – Thor Dec 02 '21 at 14:49
  • Is it possible with sed, to replace the exact number of \n? I.e. that a printf 'foo' | ... results in nothing replaced, a printf 'foo\n' | ... in one newline replaced, a printf 'foo\n\n' | ... in two replaced, and so on? – calestyo Jan 12 '22 at 00:09
  • Just like @TobiasBergkvist, I've found the same issue on macOS Big Sure. The issue here is that almost all `sed` answers expect that GNU `sed` to be installed, which is true for all Linux distributions, as well as any OS based on SysV. macOS/Darwin, as well as Solaris (and, of course, FreeBSD, NetBSD, OpenBSD...), are derivatives of BSD, and BSD `sed` doesn't have the kind of flags (and logic!) introduced by GNU `sed`... so we're out of luck :) (unless we install GNU `sed`, that is) – Gwyneth Llewelyn Jun 14 '23 at 17:20
  • This is inefficient for large input, as it reads the entire file into the pattern space before performing the replacement. For a single-character replacement, `tr` is much more efficient. – Toby Speight Jul 05 '23 at 06:44
603

Fast answer

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a create a label 'a'
  2. N append the next line to the pattern space
  3. $! if not the last line, ba branch (go to) label 'a'
  4. s substitute, /\n/ regex for new line, / / by a space, /g global match (as many times as it can)

sed will loop through step 1 to 3 until it reach the last line, getting all lines fit in the pattern space where sed will substitute all \n characters


Alternatives

All alternatives, unlike sed will not need to reach the last line to begin the process

with bash, slow

while read line; do printf "%s" "$line "; done < file

with perl, sed-like speed

perl -p -e 's/\n/ /' file

with tr, faster than sed, can replace by one character only

tr '\n' ' ' < file

with paste, tr-like speed, can replace by one character only

paste -s -d ' ' file

with awk, tr-like speed

awk 1 ORS=' ' file

Other alternative like "echo $(< file)" is slow, works only on small files and needs to process the whole file to begin the process.


Long answer from the sed FAQ 5.10

5.10. Why can't I match or delete a newline using the \n escape
sequence? Why can't I match 2 or more lines using \n?

The \n will never match the newline at the end-of-line because the
newline is always stripped off before the line is placed into the
pattern space. To get 2 or more lines into the pattern space, use
the 'N' command or something similar (such as 'H;...;g;').

Sed works like this: sed reads one line at a time, chops off the
terminating newline, puts what is left into the pattern space where
the sed script can address or change it, and when the pattern space
is printed, appends a newline to stdout (or to a file). If the
pattern space is entirely or partially deleted with 'd' or 'D', the
newline is not added in such cases. Thus, scripts like

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

will NEVER work, because the trailing newline is removed before
the line is put into the pattern space. To perform the above tasks,
use one of these scripts instead:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Since versions of sed other than GNU sed have limits to the size of
the pattern buffer, the Unix 'tr' utility is to be preferred here.
If the last line of the file contains a newline, GNU sed will add
that newline to the output but delete all others, whereas tr will
delete all newlines.

To match a block of two or more lines, there are 3 basic choices:
(1) use the 'N' command to add the Next line to the pattern space;
(2) use the 'H' command at least twice to append the current line
to the Hold space, and then retrieve the lines from the hold space
with x, g, or G; or (3) use address ranges (see section 3.3, above)
to match lines between two specified addresses.

Choices (1) and (2) will put an \n into the pattern space, where it
can be addressed as desired ('s/ABC\nXYZ/alphabet/g'). One example
of using 'N' to delete a block of lines appears in section 4.13
("How do I delete a block of specific consecutive lines?"). This
example can be modified by changing the delete command to something
else, like 'p' (print), 'i' (insert), 'c' (change), 'a' (append),
or 's' (substitute).

Choice (3) will not put an \n into the pattern space, but it does
match a block of consecutive lines, so it may be that you don't
even need the \n to find what you're looking for. Since GNU sed
version 3.02.80 now supports this syntax:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

in addition to the traditional '/from here/,/to there/{...}' range
addresses, it may be possible to avoid the use of \n entirely.

Community
  • 1
  • 1
hdorio
  • 12,902
  • 5
  • 34
  • 34
  • Thanks for the paste command. I didn't know that one. I have a file with some URLs and I wanted to open them all at once in Chrome browser. So I did (on Mac OS X): `paste -s -d ' ' url.txt | xargs open` Works great. – xlttj Jan 07 '12 at 14:36
  • @xl-t you should use `xargs -a url.txt open` instead – hdorio Feb 09 '12 at 23:28
  • Good answer. There is a slight problem in the bash alternative. It will fail on lines which are interpreted as switches to echo. This is why I never use echo to print variable data. Use `printf '%s' "$line "` instead. – Pianosaurus Jun 28 '12 at 17:03
  • 13
    `tr` was a great idea, and your overall coverage makes for a top-quality answer. – New Alexandria Jan 06 '13 at 17:57
  • 3
    +1 for using ([standard utility](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/paste.html)) `paste`... and all the others! – Totor Mar 15 '13 at 11:10
  • Does not work with colored output. I tried everything on this Q&A and nothing worked when the output is ansi colored. Tested on Ubuntu 13.04 – Leo Gallucci Dec 09 '13 at 22:51
  • 1
    @elgalu try this http://unix.stackexchange.com/questions/4527/program-that-passes-stdin-to-stdout-with-color-codes-stripped – hdorio Dec 11 '13 at 09:36
  • 4
    The best part about this answer is that the "long answer" explains exactly how and why the command works. – pdwalker May 02 '14 at 11:20
  • 5
    This may be the most helpful of the thousands of answers I've read on stackexchange. I need to match multiple characters across lines. No previous sed examples covered multi-lines and tr can't handle multiple character matching. Perl looks good, but isn't working as I expect. I'd vote this answer up several times if I could. – mightypile Jun 29 '15 at 23:37
  • 1
    I needed to replace with multiple characters, and I really enjoyed the depth and organization of this answer. My sample command was this one: `awk 1 ORS='\\\n'`. Read what the `1` means from Thor's answer, the true condition of the awk program simply causing each line of input to be printed. – Pysis Nov 15 '17 at 14:17
  • The Perl solution needs the `-0777` flag so that it processes the whole file at once, i.e. `perl -0777 -p -e 's/\n/ /' file` – caw Sep 20 '21 at 02:58
  • Amazing how such a simple case scenario can require an extraordinary amount of coding and even more explanations! But I'm profusely grateful for your answer; I'm always amused by regexps and what amazing things they're able to perform... so long as we're expecting the syntax to be consistent among tools. Clearly, `sed` has its own way of doing its magic, and your detailed explanation showed me _why_ it works 'differently from expected' (so to speak). Why exactly `sed` has this concept of streams-separated-by-newlines is, of course, historic. – Gwyneth Llewelyn Jun 14 '23 at 17:26
250

A shorter awk alternative:

awk 1 ORS=' '

Explanation

An awk program is built up of rules which consist of conditional code-blocks, i.e.:

condition { code-block }

If the code-block is omitted, the default is used: { print $0 }. Thus, the 1 is interpreted as a true condition and print $0 is executed for each line.

When awk reads the input it splits it into records based on the value of RS (Record Separator), which by default is a newline, thus awk will by default parse the input line-wise. The splitting also involves stripping off RS from the input record.

Now, when printing a record, ORS (Output Record Separator) is appended to it, default is again a newline. So by changing ORS to a space all newlines are changed to spaces.

Thor
  • 45,082
  • 11
  • 119
  • 130
  • 6
    I like a lot this simple solution, which is much more readable, than others – Fedir RYKHTIK Jul 30 '13 at 13:29
  • 11
    If it makes more sense, this could effectively be written as: `awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt` (adding an ending newline just to illustrate begin/end); the "1" evaluates to `true` (process the line) and `print` (print the line). A conditional could also be added to this expression, e.g., only working on lines matching a pattern: `awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '` – michael Sep 19 '14 at 01:22
  • 2
    You can do it more simle: `code` awk 'ORS=" "' file.txt `code` – Udi Mar 28 '18 at 15:52
  • When using awk like this then, unfortunately, the last line feed in the file is deleted, too. See Patrick Dark answer above about using 'tr' in a subshell like ` cat file | echo $(tr "\012" " ") ` which does the trick. Nifty. – Bernie Reiter Mar 28 '19 at 11:54
  • Unlike several of the other options I tried, this works in a `busybox` shell environment. – Dan Pritts Feb 16 '21 at 17:29
  • 1
    Why does the `ORS=' '` work at the end? Is it part of the program or being interpreted as an option? I would have thought you'd need to put it in a `BEGIN` block or as an option before the program like `awk -v ORS=' ' 1`. I can't figure out exactly how awk is parsing `awk 1 ORS=' '`. – Jonah May 12 '21 at 14:08
  • 2
    @Jonah: this is an alternate way of setting variables, see e.g. [the GNU awk manual](https://www.gnu.org/software/gawk/manual/gawk.html#Other-Arguments) – Thor May 13 '21 at 15:36
  • This solution also has the advantage that you can easily replace each newline with more than one character. – pglezen Apr 11 '23 at 18:30
250

GNU sed has an option, -z, for null-separated records (lines). You can just call:

sed -z 's/\n/ /g'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JJoao
  • 4,891
  • 1
  • 18
  • 20
  • 6
    Even if the input does contain nulls, they will be preserved (as record delimiters). – Toby Speight Feb 16 '16 at 17:42
  • 7
    Won't this load the whole input if there're no nulls? In this case processing a multi-gigabyte file may be crashy. – Ruslan Mar 04 '16 at 09:43
  • 5
    @Ruslan, yes it loads the whole input. This solution is not a good idea for multi-gigabyte files. – JJoao Mar 04 '16 at 09:50
  • 21
    This is seriously the **best** answer. The other expressions are too contorted to remember. @JJoao You can use it with `-u, --unbuffered`. The `man` mage states: "load minimal amounts of data from the input files and flush the output buffers more often". – not2qubit Feb 21 '18 at 21:10
  • so. much. this. – sjas Mar 07 '19 at 15:07
  • 1
    @Ruslan If you have a multi-gigabyte textfile, you don't want to use `sed` anyway, even in line-based mode, as `sed` is annoying slow on large input. – vog Nov 26 '19 at 23:19
  • This is the most direct response to the original question (sure, there are many ways to replace newlines in files, but the question asked for how to do it with sed). This is a commandline switch I wish I knew about 15 years ago. – Luke Hutchison Apr 30 '21 at 02:05
  • 2
    The little used `y` command does the job too `sed -z 'y/\n/ /' file`. – potong Jun 03 '21 at 12:10
  • @potong, very cool! thank you. – JJoao Oct 04 '21 at 15:11
  • To exclude a trailing newline, try `sed -z 's/\n$/\x00/; s/\n/ /g; s/\x00$/\n/'` – aggu Jan 01 '22 at 04:33
  • 1
    [The -z option will cause sed to separate lines based on the ASCII NUL character instead of the newline character. Just like normal newline based processing, the NUL character is removed (if present) from the input line and added back accordingly when the processed line is printed.](https://learnbyexample.github.io/learn_gnused/z-s-and-f-command-line-options.html#:~:text=The%20%2Dz%20option%20will%20cause,the%20processed%20line%20is%20printed.) – RexYuan Dec 28 '22 at 18:21
100

The Perl version works the way you expected.

perl -i -p -e 's/\n//' file

As pointed out in the comments, it's worth noting that this edits in place. -i.bak will give you a backup of the original file before the replacement in case your regular expression isn't as smart as you thought.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
  • 28
    Please at least mention that `-i` without a suffix makes *no backup*. `-i.bak` protects you from an easy, ugly mistake (say, forgetting to type `-p` and zeroing out the file). – Telemachus Aug 09 '09 at 20:31
  • 7
    @Telemachus: It's a fair point, but it can be argued either way. The main reason I didn't mention it is that the sed example in the OP's question doesn't make backups, so it seems superfluous here. The other reason is that I've never actually used the backup functionality (I find automatic backups annoying, actually), so I always forget it's there. The third reason is it makes my command line four characters longer. For better or worse (probably worse), I'm a compulsive minimalist; I just prefer brevity. I realise you don't agree. I will try my best to remember to warn about backups in future. – ire_and_curses Aug 09 '09 at 20:53
  • 7
    @Ire_and_curses: Actually, you just made a damn good argument for ignoring me. That is, you have reasons for your choices, and whether or not I agree with the choices, I certainly respect that. I'm not sure entirely why, but I've been on a tear about this particular thing lately (the `-i` flag in Perl without a suffix). I'm sure I'll find something else to obsess about soon enough. :) – Telemachus Aug 09 '09 at 21:36
  • It's really unfortunate that this doesn't work with stdin by specifying `-` for filename. Is there a way to do that? That's my go-to way to not worry about modifying a file is using a pipeline that starts with cat. – Steven Lu Apr 10 '19 at 02:57
  • @StevenLu Perl will read from STDIN by default if no filenames are provided. So you could do e.g. `perl -i -p -e 's/\n//' < infile > outfile` – ire_and_curses Apr 10 '19 at 15:47
  • I just know from this answer and comments that `-i` without suffix will be write to the file. I was copied the code from somewhere else that is use `source > destination` but if source and destination are the same file, it will make the file **blank**. So, `-i` like this answer can help. Thanks a lot. – vee Aug 16 '21 at 05:54
  • This solution needs the `-0777` flag so that Perl processes the whole file at once, i.e. `perl -0777 -i -p -e 's/\n//' file` – caw Sep 20 '21 at 03:01
52

Who needs sed? Here is the bash way:

cat test.txt |  while read line; do echo -n "$line "; done
xav
  • 5,452
  • 7
  • 48
  • 57
commonpike
  • 10,499
  • 4
  • 65
  • 58
31

In order to replace all newlines with spaces using awk, without reading the whole file into memory:

awk '{printf "%s ", $0}' inputfile

If you want a final newline:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

You can use a character other than space:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • 2
    `END{ print ""}` is a shorter alternative for a trailing newline. –  Dec 15 '19 at 23:41
28
tr '\n' ' ' 

is the command.

Simple and easy to use.

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Dheeraj R
  • 701
  • 9
  • 17
19

Three things.

  1. tr (or cat, etc.) is absolutely not needed. (GNU) sed and (GNU) awk, when combined, can do 99.9% of any text processing you need.

  2. stream != line based. ed is a line-based editor. sed is not. See sed lecture for more information on the difference. Most people confuse sed to be line-based because it is, by default, not very greedy in its pattern matching for SIMPLE matches - for instance, when doing pattern searching and replacing by one or two characters, it by default only replaces on the first match it finds (unless specified otherwise by the global command). There would not even be a global command if it were line-based rather than STREAM-based, because it would evaluate only lines at a time. Try running ed; you'll notice the difference. ed is pretty useful if you want to iterate over specific lines (such as in a for-loop), but most of the times you'll just want sed.

  3. That being said,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    works just fine in GNU sed version 4.2.1. The above command will replace all newlines with spaces. It's ugly and a bit cumbersome to type in, but it works just fine. The {}'s can be left out, as they're only included for sanity reasons.

7ochem
  • 2,183
  • 1
  • 34
  • 42
brent saner
  • 412
  • 1
  • 5
  • 9
  • 5
    As a person who only knows enough `sed` to do basic stuff, I have to say it's more than about what you *can* do with `sed` but rather how easy it is to understand what is going on. I have a very hard time working with `sed` so I would prefer a simpler command when I can use it. – Nate Mar 04 '14 at 19:15
  • Using `t q` as conditional jump this works with a pattern like `s/\n / /` (to join all lines which begin with a space) without reading the whole file into memory. Handy when transforming multi megabyte files. – textshell Jun 26 '15 at 11:17
  • The article you've linked does not reflect what you are saying – hek2mgl Mar 29 '16 at 22:33
  • 3
    This is almost 800 times slower than the accepted answer on large input. This is due to running substitute for every line on increasingly larger input. – Thor Nov 03 '16 at 20:17
16

Why didn't I find a simple solution with awk?

awk '{printf $0}' file

printf will print the every line without newlines, if you want to separate the original lines with a space or other:

awk '{printf $0 " "}' file
Itachi
  • 5,777
  • 2
  • 37
  • 69
15

The answer with the :a label ...

How can I replace a newline (\n) using sed?

... does not work in freebsd 7.2 on the command line:

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'
foo
bar

But does if you put the sed script in a file or use -e to "build" the sed script...

> (echo foo; echo bar) | sed -e :a -e N -e '$!ba' -e 's/\n/ /g'
foo bar

or ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

Maybe the sed in OS X is similar.

Community
  • 1
  • 1
Juan
  • 1,204
  • 1
  • 11
  • 25
15

Easy-to-understand Solution

I had this problem. The kicker was that I needed the solution to work on BSD's (Mac OS X) and GNU's (Linux and Cygwin) sed and tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Output:

foo
bar
baz

(has trailing newline)

It works on Linux, OS X, and BSD - even without UTF-8 support or with a crappy terminal.

  1. Use tr to swap the newline with another character.

    NULL (\000 or \x00) is nice because it doesn't need UTF-8 support and it's not likely to be used.

  2. Use sed to match the NULL

  3. Use tr to swap back extra newlines if you need them

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • 1
    A subtle note on nomenclature: the character `\000` is commonly referred to as `NUL` (one L), and `NULL` is generally used when talking about a zero-_pointer_ (in C/C++). – sqweek Feb 29 '16 at 08:59
14

You can use xargs:

seq 10 | xargs

or

seq 10 | xargs echo -n
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vytenis Bivainis
  • 2,308
  • 21
  • 28
14
cat file | xargs

for the sake of completeness

nefuson
  • 171
  • 1
  • 4
13

If you are unfortunate enough to have to deal with Windows line endings, you need to remove the \r and the \n:

tr '\r\n' ' ' < $input > $output
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
StevenWernerCS
  • 839
  • 9
  • 15
  • This replaces `[` with a space, and `\r` with a space, and `\n` with a space, and `]` with a space. `tr -d '\r\n' – tripleee Dec 29 '19 at 10:39
  • Thanks, fixed it. just don't put [], and tr does respect \n & \r as new line and returns. are there systems where tr doesn't? – StevenWernerCS Jul 16 '20 at 01:08
  • They ase oretty ubiquitous these days, but I think I can remember systems where they didn't work (dinosaurs like HP-UX and AIX and Irix maybe?) – tripleee Jul 16 '20 at 05:48
9

I'm not an expert, but I guess in sed you'd first need to append the next line into the pattern space, bij using "N". From the section "Multiline Pattern Space" in "Advanced sed Commands" of the book sed & awk (Dale Dougherty and Arnold Robbins; O'Reilly 1997; page 107 in the preview):

The multiline Next (N) command creates a multiline pattern space by reading a new line of input and appending it to the contents of the pattern space. The original contents of pattern space and the new input line are separated by a newline. The embedded newline character can be matched in patterns by the escape sequence "\n". In a multiline pattern space, the metacharacter "^" matches the very first character of the pattern space, and not the character(s) following any embedded newline(s). Similarly, "$" matches only the final newline in the pattern space, and not any embedded newline(s). After the Next command is executed, control is then passed to subsequent commands in the script.

From man sed:

[2addr]N

Append the next line of input to the pattern space, using an embedded newline character to separate the appended material from the original contents. Note that the current line number changes.

I've used this to search (multiple) badly formatted log files, in which the search string may be found on an "orphaned" next line.

Community
  • 1
  • 1
Arjan
  • 22,808
  • 11
  • 61
  • 71
7

You can also use this method:

sed 'x;G;1!h;s/\n/ /g;$!d'

Explanation

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting the next line until the
      the last line.

Flow

When the first line get from the input, an exchange is made, so 1 goes to hold space and \n comes to pattern space, appending the hold space to pattern space, and a substitution is performed and deletes the pattern space.

During the second line, an exchange is made, 2 goes to hold space and 1 comes to the pattern space, G append the hold space into the pattern space, h copy the pattern to it, the substitution is made and deleted. This operation is continued until EOF is reached and prints the exact result.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kalanidhi
  • 4,902
  • 27
  • 42
7

In response to the "tr" solution above, on Windows (probably using the Gnuwin32 version of tr), the proposed solution:

tr '\n' ' ' < input

was not working for me, it'd either error or actually replace the \n w/ '' for some reason.

Using another feature of tr, the "delete" option -d did work though:

tr -d '\n' < input

or '\r\n' instead of '\n'

John Lawler
  • 71
  • 1
  • 1
  • 3
    On Windows, you probably need to use `tr "\n" " " < input`. The Windows shell (cmd.exe) doesn't treat the apostrophe as a quoting character. – Keith Thompson Aug 24 '11 at 14:25
  • No, in Windows 10 Ubuntu subsystem, you need to use ```tr "\n\r" " " < input.txt > output.txt``` – user1491819 Sep 29 '17 at 03:55
  • This works on Windows 10 using Gnuwin32: `cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt` . Or, instead of Gnuwin32, use Gow (Gnu on Windows), https://github.com/bmatzelle/gow/wiki – Alchemistmatt Jun 13 '18 at 23:15
7

I used a hybrid approach to get around the newline thing by using tr to replace newlines with tabs, then replacing tabs with whatever I want. In this case, "
" since I'm trying to generate HTML breaks.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rfengr
  • 79
  • 1
  • 1
5

Bullet-proof solution. Binary-data-safe and POSIX-compliant, but slow.

POSIX sed requires input according to the POSIX text file and POSIX line definitions, so NULL-bytes and too long lines are not allowed and each line must end with a newline (including the last line). This makes it hard to use sed for processing arbitrary input data.

The following solution avoids sed and instead converts the input bytes to octal codes and then to bytes again, but intercepts octal code 012 (newline) and outputs the replacement string in place of it. As far as I can tell the solution is POSIX-compliant, so it should work on a wide variety of platforms.

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

POSIX reference documentation: sh, shell command language, od, tr, grep, read, [, printf.

Both read, [, and printf are built-ins in at least bash, but that is probably not guaranteed by POSIX, so on some platforms it could be that each input byte will start one or more new processes, which will slow things down. Even in bash this solution only reaches about 50 kB/s, so it's not suited for large files.

Tested on Ubuntu (bash, dash, and busybox), FreeBSD, and OpenBSD.

5

Finds and replaces using allowing \n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

Marker

Becomes

# Marker Comment

Marker

Proximo
  • 6,235
  • 11
  • 49
  • 67
5

In some situations maybe you can change RS to some other string or character. This way, \n is available for sub/gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

The power of shell scripting is that if you do not know how to do it in one way you can do it in another way. And many times you have more things to take into account than make a complex solution on a simple problem.

Regarding the thing that gawk is slow... and reads the file into memory, I do not know this, but to me gawk seems to work with one line at the time and is very very fast (not that fast as some of the others, but the time to write and test also counts).

I process MB and even GB of data, and the only limit I found is line size.

slayedbylucifer
  • 22,878
  • 16
  • 94
  • 123
mor
  • 51
  • 1
  • 1
4

You could use xargs — it will replace \n with a space by default.

However, it would have problems if your input has any case of an unterminated quote, e.g. if the quote signs on a given line don't match.

cnst
  • 25,870
  • 6
  • 90
  • 122
3

Replace newlines with any string, and replace the last newline too

The pure tr solutions can only replace with a single character, and the pure sed solutions don't replace the last newline of the input. The following solution fixes these problems, and seems to be safe for binary data (even with a UTF-8 locale):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

Result:

1<br>2<br>3<br>
  • This is bad because it will produce unwanted output on any input containing `@` – Steven Lu Jun 22 '13 at 17:38
  • @StevenLu: No, `@` in the input is OK. It gets escaped to `%a` and back again. The solution might not be completely POSIX compliant, though (NULL-bytes not allowed so not good for binary data, and all lines must end with newline so the `tr` output is not really valid). – Håkon A. Hjortland Jun 27 '13 at 00:48
  • Ah. I see you've fixed it up. Kinda convoluted for what should be a simple operation, but good work. – Steven Lu Jun 27 '13 at 02:48
3

It is sed that introduces the new-lines after "normal" substitution. First, it trims the new-line char, then it processes according to your instructions, then it introduces a new-line.

Using sed you can replace "the end" of a line (not the new-line char) after being trimmed, with a string of your choice, for each input line; but, sed will output different lines. For example, suppose you wanted to replace the "end of line" with "===" (more general than a replacing with a single space):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

To replace the new-line char with the string, you can, inefficiently though, use tr , as pointed before, to replace the newline-chars with a "special char" and then use sed to replace that special char with the string you want.

For example:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$
Robert Vila
  • 221
  • 3
  • 2
3

On Mac OS X (using FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta
bashfu
  • 249
  • 1
  • 3
  • 2
3

Another GNU sed method, almost the same as Zsolt Botykai's answer, but this uses sed's less-frequently used y (transliterate) command, which saves one byte of code (the trailing g):

sed ':a;N;$!ba;y/\n/ /'

One would hope y would run faster than s, (perhaps at tr speeds, 20x faster), but in GNU sed v4.2.2 y is about 4% slower than s.


More portable BSD sed version:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
agc
  • 7,973
  • 2
  • 29
  • 50
  • 2
    With BSD sed `y` is ca 15% faster. See [this answer](http://stackoverflow.com/a/1474512/1331399) for a working example. – Thor Nov 03 '16 at 19:01
  • Also, with BSD sed commands need to terminate after a label, so `sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'` would be the way to go. – ghoti Sep 13 '18 at 04:26
3

You can also use the Standard Text Editor:

printf '%s\n' '%s/$/ /' '%j' 'w' | ed -s file

Note: this saves the result back to file.

As with most sed answers here, this solution suffers from having to load the whole file into memory first.

Thor
  • 45,082
  • 11
  • 119
  • 130
3

To remove empty lines:

sed -n "s/^$//;t;p;"
kralyk
  • 4,249
  • 1
  • 32
  • 34
3

Using Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"
kralyk
  • 4,249
  • 1
  • 32
  • 34
  • 2
    You don't need to escape the quotation marks and dollar sign if you change the outer ones to single quotes. The letter "o" is usually considered a bad choice as a variable name since it can be confused with the digit "0". You also don't need to initialize your variable, it defaults to a null string. However, if you don't want an extraneous leading space: `awk '{s = s sp $0; sp = " "} END {print s}'`. However, see my answer for a way to use awk without reading the whole file into memory. – Dennis Williamson Mar 30 '12 at 06:34
  • **Please** check out [Thor's answer](http://stackoverflow.com/a/14853319/2451238) instead. It is way more efficient, readable and just _better_ by all means to compared this approach (even though this _would_ work)! – mschilli Sep 02 '13 at 17:03
  • Dude, I get it. No need to rub it in my face :-) Thor's answer is way above on the page anyway (which is right), so what do you care? – kralyk Sep 03 '13 at 13:28
3

A solution I particularly like is to append all the file in the hold space and replace all newlines at the end of file:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

However, someone said me the hold space can be finite in some sed implementations.

brandizzi
  • 26,083
  • 8
  • 103
  • 158
  • 1
    the replacement with an empty string in your answer conceals the fact that always using H to append to the hold space means that the hold space will start with a newline. To avoid this, you need to use `1h;2,$H;${x;s/\n/x/g;p}` – Jeff Jul 09 '16 at 06:34
2
sed '1h;1!H;$!d
     x;s/\n/ /g' YourFile

This does not work for huge files (buffer limit), but it is very efficient if there is enough memory to hold the file. (Correction H-> 1h;1!H after the good remark of @hilojack )

Another version that change new line while reading (more cpu, less memory)

 sed ':loop
 $! N
 s/\n/ /
 t loop' YourFile
Thor
  • 45,082
  • 11
  • 119
  • 130
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
  • It is not efficient as the example `sed ':a;N;$!ba;s/\n/ /g'`. On the other hand the output has an extra space character `` – ahuigo Jun 19 '15 at 09:59
  • 1
    The loop version is similar to [this answer](http://stackoverflow.com/a/5847965/1331399) and as I noted in the comments there, it is ca 800 times slower. – Thor Nov 03 '16 at 19:14
  • `+1` for the first version as an instructive alternative to the `':a;N;$!ba;s/\n/ /g'` script. But `-1` for the loop version due to the reason mentioned by @Thor, don't use the loop variant, it will save neither CPU nor memory. – coldfix Dec 02 '21 at 13:32
2

This might work for you (GNU sed):

sed 'H;$!d;x;:a;s/^((.).*)\2/\1 /;ta;s/.//' file

The H command prepends a newline to the pattern space and then appends the result to the hold space. The normal flow of sed is to remove the following newline from each line, thus this will introduce a newline to the start of the hold space and the replicate the remainder of the file. Once the file has been slurped into the hold space, swap the hold space with the patten space and then use pattern matching to replace all original newlines with spaces. Finally, remove the introduced newline.

This has the advantage of never actually entering a newline string within the sed commands.

Alternative:

sed 'H;$!d;x;y/\n/ /;s/.//' file

Or:

sed 'H;1h;$!d;x;y/\n/ /' file
potong
  • 55,640
  • 6
  • 51
  • 83
1

@OP, if you want to replace newlines in a file, you can just use dos2unix (or unix2dox)

dos2unix yourfile yourfile
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • Can you add some more information to your answer (a link may or may not be sufficient)? E.g. where is dos2unix to be had? Is it a stand-alone program? Is it part of a bigger package? What platforms does it run on (only Unix? only Windows?) – Peter Mortensen Mar 31 '15 at 08:11
  • 3
    This only gets rid of \r -- not \n. I use sed all the time for this... *sed -i -e 's/\r$//' foo* is more robust than these tools for me. – Michael Back Nov 26 '15 at 04:13
1

Yet another option:

tr -s "[:space:]" " " < filename > filename2 && mv filename2 filename

Where tr -s is for:

-s, --squeeze-repeats replace each sequence of a repeated character that is listed in the last specified SET, with a single occurrence of that character

This uses replaces all whitespace sequences in the file with a single space, writes result to a new file, then renames new file back to original name.

Danny Varod
  • 17,324
  • 5
  • 69
  • 111
0

Most of the previous sed command examples do not work for me in my Unix box and give me error message:

Label too long: {:q;N;s/\n/ /g;t q}

This works in all Unix/Linux environments:

line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt)
echo $line |sed 's/ //g' > sortedoutput.txt

The first line will remove all the new line from file yoursourcefile.txt and will produce a single line. And second sed command will remove all the spaces from it.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17
  • 1
    The "Label too long" probably means you are on BSD `sed` and trying to use GNU `sed` syntax. Try adding a newline after the label, as suggested in another answer. – tripleee Dec 29 '19 at 11:27
-1

This is really simple... I really get irritated when I found the solution. There was just one more back slash missing. This is it:

sed -i "s/\\\\\n//g" filename
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sabby
  • 9
  • Your scientists were so preoccupied with whether they could, they didn’t stop to think if they should. – DevOops Jul 27 '23 at 23:41
-2

The following is a lot simpler than most answers. Also, it is working:

echo `sed -e 's/$/\ |\ /g' file`
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 8
    This isn't working, since it doesn't *replace* the newline, but prepend some text to each line. – leemes Jun 14 '12 at 01:48
-2

Here is sed without buffers (good for real time output).
Example: replacing \n with <br/> break in HTML

echo -e "1\n2\n3" | sed 's/.*$/&<br\/>/'
xav
  • 5,452
  • 7
  • 48
  • 57
Tiago
  • 17
-3
sed -i ':a;N;$!ba;s/\n/,/g' test.txt

tr "\n" <file name>
Poo
  • 213
  • 1
  • 6
  • 18
-7

In the sed replacement part, type backslash, hit enter to go to the second line, then end it with /g':

sed 's/>/\
/g'

[root@localhost ~]# echo "1st</first>2nd</second>3rd</third>" | sed 's/>/\
> /g'
1st</first
2nd</second
3rd</third

[root@localhost ~]#
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
blah
  • 3
  • 1
  • One thing to note though is that for portability, sometimes using a new line in the script (not \n) is necessary. With some trickery you could also insert a literal `\r`. I mean inserting the real characters into the script file, not escapes. – akostadinov Jun 05 '14 at 06:41
-7

Try this:

echo "a,b"|sed 's/,/\r\n/'
animuson
  • 53,861
  • 28
  • 137
  • 147