52

a bash commands outputs this:

Runtime Name: vmhba2:C0:T3:L14
Group State: active
Runtime Name: vmhba3:C0:T0:L14
Group State: active unoptimized
Runtime Name: vmhba2:C0:T1:L14
Group State: active unoptimized
Runtime Name: vmhba3:C0:T3:L14
Group State: active
Runtime Name: vmhba2:C0:T2:L14
Group State: active

I'd like to pipe it to something to make it look like this:

Runtime Name: vmhba2:C0:T1:L14 Group State: active 
Runtime Name: vmhba3:C0:T3:L14 Group State: active unoptimized
Runtime Name: vmhba2:C0:T2:L14 Group State: active
[...]

i.e. remove every other newline

I tried ... |tr "\nGroup" " " but it removed all newlines and ate up some other letters as well. thanks

2
  • 3
    tr is entirely character based: you asked tr to remove newlines and all 'G', 'r', 'o', 'u', and 'p'. Mar 30, 2012 at 1:01
  • Are you looking for every other (single) newline at the end of a line, or multiple newlines like \n\n, or both?
    – smci
    Feb 10, 2020 at 23:18

8 Answers 8

101

can't test right now, but

... | paste - - 

should do it

3
  • 8
    +1 - works and is elegant. (It puts a tab between the lines - paste -d ' ' - - will add a space instead if required)
    – cyberx86
    Mar 30, 2012 at 1:20
  • 6
    Could you please explain how does the command work? Why are there two -? Thanks
    – bbaja42
    Mar 30, 2012 at 8:55
  • 12
    paste is used to concatenate corresponding lines from files: paste file1 file2 file3 .... If one of the "file" arguments is "-", then lines are read from standard input. If there are 2 "-" arguments, then paste takes 2 lines from stdin. And so on. See the man page. Mar 30, 2012 at 10:33
12

One possibility is:

awk 'ORS=NR%2?" ":"\n"'

If the line number is evenly divisible by 2, end with a new line, otherwise, end with a space.

(Tested on: CentOS 6, GNU Awk 3.1.7)

Using sed (see explanation):

sed ':a;N;$!ba;s/\nGroup/ Group/g'

Further reading:

1
  • The second link to linux.dsplabs.com.au is broken
    – smci
    Feb 9, 2020 at 19:44
9

If you want to use sed, there's no reason to read the whole file into memory. You can merge every other line like this:

sed 'N;s/\n/ /' inputfile

Use any character you'd like instead of the space.

Here's another way using awk:

awk '{printf "%s", $0; if (getline) print " " $0; else printf "\n"}' inputfile

The if/else handles the case where there is an odd number of lines in the file. Without it, the odd last line gets printed twice. Otherwise, for comparison, you could do:

awk '{printf "%s", $0; getline; print " " $0}'
1
  • 1
    A late comment: 1) always use a format specifier for printf in case the string has percent signs, 2) to avoid the duplicated last line, set $0 to "" -- awk '{printf "%s", $0; $0=""; getline; print " " $0}' Dec 10, 2012 at 21:47
4

The most idiomatic way to do it in awk is as follows:

awk 'ORS=NR%2?FS:RS' file

It outputs:

Runtime Name: vmhba2:C0:T3:L14 Group State: active
Runtime Name: vmhba3:C0:T0:L14 Group State: active unoptimized
Runtime Name: vmhba2:C0:T1:L14 Group State: active unoptimized
Runtime Name: vmhba3:C0:T3:L14 Group State: active
Runtime Name: vmhba2:C0:T2:L14 Group State: active

To explain it we need to define each one of the built-in variables:

  • RS record separator. Defaults to \n (new line).
  • ORS output record separator. Defaults to \n (new line).
  • FS field separator. Defaults to (space).
  • NR number of record.

As the default record separator is the new line, a record is, as default, a line.

NR%2 is the modulus of NR/2, so that it will be either 0 or 1. 0 for even lines and 1 for odd lines.

var=condition?condition_if_true:condition_if_false is the ternary operator.

All together, saying ORS=NR%2?FS:RS we are defining the output record separator:

  • if the number of record is on the form 2k + 1, that is, on even lines, then the output record separators is set to FS, that is, a space.
  • if the number of record is on the form 2k, that is, on odd lines, then the output record separators is set to RS, that is, a new line.

This way, odd lines end with a space, that is then joined with the next line. After that line, a new line is printed.

More info in Idiomatic awk.

1
  • This also cunningly relies on the fact that the expression also results in either FS or RS, which are (evidently) both truthy. If the expression returned something falsy (e.g. (ORS=...)&&0, nothing would print.
    – mwfearnley
    Mar 25, 2022 at 10:56
3

This works for me on Linux:

... | tr "\\n" " "

This replaces an empty space for a newline character; you must escape the newline character for things to work correctly.

1
  • 1
    This removes every newline, not every other newline.
    – Trenton
    Feb 23, 2017 at 22:20
2

In bash:

... | while read l1; do read l2; echo "$l1 $l2"; done
1

If Perl is an option:

perl -pe 's/\n/ / if $. % 2 == 1' file

s/\n/ / replaces newline with space
$. is the line number

-2

How about using grep ?

.. | grep -v '^Group State'
2
  • 1
    That eliminates the alternate lines. The OP wants them appended. Mar 30, 2012 at 6:51
  • Yeah, after re-reading the question I just realized that :)
    – pkhamre
    Mar 30, 2012 at 6:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .