1

This question already has an answer here:

echo "hi,my,name,is" | sed 's/,/\n/g' >out.txt

yields:

hi
my
name
is

But in reverse:

sed 's/\n/,/g' out.txt

yields:

hi
my
name
is

Why doesn't sed revert the operation with an inversion of the replace operation?

marked as duplicate by don_crissti, DopeGhoti, Jeff Schaller, G-Man, DarkHeart Mar 10 '18 at 12:36

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • because sed/awk strips the record separator (newline in your case) and adds back while printing... perl/ruby wont.. so you'd get your inversion there.. – Sundeep Mar 9 '18 at 5:42
5

Try:

$ sed 'H;1h;$!d;x; s/\n/,/g' out.txt
hi,my,name,is

By default, sed reads in only one line at a time, processes it, and prints it. Since a single line never has a newline character, the command s/\n/,/g does nothing. The solution, as above, is to read the whole file in at once and then do s/\n/,/g.

The commands H;1h;$!d;x read the whole file in at once. It is probably simplest to think of this as an idiom. If you really want to know the gory details:

  • H - Append current line to hold space
  • 1h - If this is the first line, overwrite the hold space with it
  • $!d - If this is not the last line, delete pattern space and jump to the next line.
  • x - Exchange hold and pattern space to put whole file in pattern space

Alternative: awk

$ awk 'NR>1{printf ","} {printf "%s",$0} END{print""}' out.txt
hi,my,name,is

Or:

$ awk '{printf "%s%s",(NR==1?"":","),$0} END{print""}' out.txt
hi,my,name,is
  • 1
    Or just tr '\n' , – Sparhawk Mar 9 '18 at 4:01
  • @Sparhawk Very true. But, as you saw in the title of this question, the OP knew about the tr approach. He was looking for a better understanding of sed. – John1024 Mar 9 '18 at 4:18
  • Arrgghh, yes, true. I missed that, sorry. (+1) – Sparhawk Mar 9 '18 at 4:24
  • Three more awk ways: {printf "%s",t $0; t=","} END{print""} or {t=t "," $0} END{print substr(t,2)} optionally with redundant BEGIN{t=""} or -vt= for clarity; or on condition none of the lines are empty -vRS="" '{gsub(/\n/,","); print}' (which is almost like the sed) – dave_thompson_085 Mar 9 '18 at 6:03
1

With gnu sed

echo "hi,my,name,is" | sed 's/,/\n/g' | sed -z 's/\n/,/g'

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