bash / sed / awk / etc usuwają każdą nową linię

39

polecenia bash generują to:

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

Chciałbym przesłać go do czegoś, aby wyglądało tak:

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
[...]

tj. usuń co drugą linię

Próbowałem, ... |tr "\nGroup" " "ale usunąłem wszystkie nowe wiersze i zjadłem też kilka innych liter. dzięki

carillonator
źródło
2
trjest całkowicie oparty na znakach: poprosiłeś tr, aby usunąć znaki nowej linii oraz wszystkie „G”, „r”, „o”, „u” i „p”.
glenn jackman

Odpowiedzi:

80

nie mogę teraz przetestować, ale

... | paste - - 

powinien to zrobić

Glenn Jackman
źródło
5
+1 - działa i jest elegancki. (Umieszcza tabulator między wierszami - paste -d ' ' - -zamiast tego doda spację, jeśli jest to wymagane)
cyberx86
4
Czy możesz wyjaśnić, jak działa polecenie? Dlaczego są dwa -? Dzięki
bbaja42,
7
pastesłuży do łączenia odpowiednich linii z plików: paste file1 file2 file3 .... Jeśli jednym z argumentów „plik” jest „-”, wiersze są odczytywane ze standardowego wejścia. Jeśli są 2 argumenty „-”, wówczas wklej pobiera 2 linie ze standardowego wejścia. I tak dalej. Zobacz stronę manuala .
glenn jackman
10

Jedną z możliwości jest:

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

Jeśli numer linii jest równomiernie podzielny przez 2, zakończ nową linię, w przeciwnym razie zakończ spacją.

(Testowane na: CentOS 6, GNU Awk 3.1.7)

Za pomocą sed (patrz wyjaśnienie ):

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

Dalsza lektura:

cyberx86
źródło
8

Jeśli chcesz użyć sed, nie ma powodu, aby czytać cały plik do pamięci. Możesz scalić każdą inną linię w ten sposób:

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

Zamiast spacji użyj dowolnej postaci.

Oto inny sposób korzystania z awk:

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

Te if/elseuchwyty przypadku, gdy nie ma nieparzystą liczbę wierszy w pliku. Bez tego nieparzysta ostatnia linia jest drukowana dwukrotnie. W przeciwnym razie możesz dla porównania:

awk '{printf "%s", $0; getline; print " " $0}'
Wstrzymano do odwołania.
źródło
1
Późny komentarz: 1) zawsze używaj specyfikatora formatu dla printf w przypadku, gdy łańcuch ma znaki procentu, 2) aby uniknąć powielonego ostatniego wiersza, ustaw 0 $ na „” -awk '{printf "%s", $0; $0=""; getline; print " " $0}'
glenn jackman
3

Najbardziej idiomatyczny sposób na zrobienie tego awkjest następujący:

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

Wytwarza:

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

Aby to wyjaśnić, musimy zdefiniować każdą z wbudowanych zmiennych:

  • RSseparator rekordów. Domyślnie \n(nowa linia).
  • ORSseparator rekordów wyjściowych. Domyślnie \n(nowa linia).
  • FSseparator pola. Domyślnie (spacja).
  • NR liczba rekordów.

Ponieważ domyślnym separatorem rekordów jest nowa linia, rekord jest domyślnie linią.

NR%2jest modułem NR/2, tak że będzie albo 0albo 1. 0dla linii parzystych i 1dla linii nieparzystych.

var=condition?condition_if_true:condition_if_false jest operatorem trójskładnikowym.

Wszyscy razem, mówiąc, ORS=NR%2?FS:RSże definiujemy separator rekordu wyjściowego:

  • jeśli liczba rekordów jest w formie 2k + 1, to znaczy w liniach parzystych, to separatory rekordów wyjściowych są ustawione na FSspację.
  • jeśli liczba rekordów jest w formie 2k, to znaczy w nieparzystych liniach, to separatory rekordów wyjściowych są ustawione na RS, to znaczy nową linię.

W ten sposób nieparzyste linie kończą się spacją, która jest następnie łączona z następną linią. Po tej linii drukowana jest nowa linia.

Więcej informacji w idiomatic awk .

fedorqui
źródło
2

Działa to dla mnie w systemie Linux:

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

Zastępuje to puste miejsce dla znaku nowej linii; Państwo musi uciec znak nowej linii na rzeczy działało poprawnie.

Bret McMillan
źródło
Spowoduje to usunięcie wszelkich przełamane, nie każda inna linią.
Trenton
2

W bash:

... | while read l1; do read l2; echo "$l1 $l2"; done
jfg956
źródło
1

Jeśli Perl jest opcją:

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

s/\n/ /zastępuje znak nowej linii spacją
$.jest numerem linii

Chris Koknat
źródło
-1

Co powiesz na używanie grep?

.. | grep -v '^Group State'
pkhamre
źródło
To eliminuje alternatywne linie. OP chce, aby zostały dołączone.
Wstrzymano do odwołania.
Tak, po ponownym przeczytaniu pytania właśnie zdałem sobie sprawę, że :)
pkhamre