51

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

carillonator
  • 805
  • 3
  • 12
  • 22
  • 3
    `tr` is entirely character based: you asked tr to remove newlines and all 'G', 'r', 'o', 'u', and 'p'. – glenn jackman Mar 30 '12 at 01: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 '20 at 23:18

8 Answers8

99

can't test right now, but

... | paste - - 

should do it

glenn jackman
  • 4,320
  • 16
  • 19
  • 7
    +1 - works and is elegant. (It puts a tab between the lines - `paste -d ' ' - -` will add a space instead if required) – cyberx86 Mar 30 '12 at 01:20
  • 6
    Could you please explain how does the command work? Why are there two `-`? Thanks – bbaja42 Mar 30 '12 at 08:55
  • 11
    `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](http://man.cx/paste). – glenn jackman Mar 30 '12 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:

cyberx86
  • 20,620
  • 1
  • 60
  • 80
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}'
Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • 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}'` – glenn jackman Dec 10 '12 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.

fedorqui
  • 248
  • 4
  • 17
  • 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 '22 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.

Bret McMillan
  • 101
  • 1
  • 3
2

In bash:

... | while read l1; do read l2; echo "$l1 $l2"; done
jfg956
  • 1,116
  • 1
  • 8
  • 12
1

If Perl is an option:

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

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

Chris Koknat
  • 111
  • 3
-2

How about using grep ?

.. | grep -v '^Group State'
pkhamre
  • 5,900
  • 3
  • 15
  • 27