Jak połączyć wiele wierszy wyniku w jeden wiersz?


158

Jeśli uruchomię polecenie cat file | grep pattern, otrzymam wiele wierszy danych wyjściowych. Jak połączyć wszystkie wiersze w jeden wiersz, skutecznie zastępując każdy "\n"z "\" "(koniec ze "spacją)?

cat file | grep pattern | xargs sed s/\n/ /g nie działa dla mnie.


Przy okazji: (1) musisz umieścić swój sedskrypt w apostrofach, aby Bash z nim nie zadzierał (ponieważ sed s/\n/ /gwywołania sedz dwoma argumentami, mianowicie s/n/i /g); (2) Ponieważ chcesz wyjście cat file | grep patternza wejście do sed, a nie argumenty do sed, trzeba wyeliminować xargs; i (3) nie ma takiej potrzeby cat, ponieważ grepmoże przyjąć nazwę pliku jako drugi argument. Więc powinieneś był spróbować grep pattern file | sed 's/\n/ /g'. (W tym przypadku to by nie zadziałało, z powodów podanych w powyższym linku, ale teraz wiesz na przyszłość.)
ruakh


Pytanie z 68 głosami (140 tys. Wyświetleń) powielone z postem, który ma tylko 1 głos (12 tys. Wyświetleń)? To nie jest w porządku.
kenorb

Odpowiedzi:


231

Służy tr '\n' ' 'do tłumaczenia wszystkich znaków nowej linii na spacje:

$ grep pattern file | tr '\n' ' '

Uwaga: grepczyta pliki, catłączy pliki. Nie cat file | grep!

Edytować:

trobsługuje tylko tłumaczenia pojedynczych znaków. Możesz użyć awkdo zmiany separatora rekordów wyjściowych, takich jak:

$ grep pattern file | awk '{print}' ORS='" '

To zmieniłoby:

one
two 
three

do:

one" two" three" 

3
Takie podejście kończy się niepożądaną przestrzenią na końcu.
sorin

1
Musisz dodać echo ""na końcu, aby dodać nową linię przed tekstem zachęty.
nexayq

1
Działa to ładnie, ale nie chcę, aby separator pojawiał się na ostatnim wpisie. Na przykład, na twój ", wygląda to tak one" two" three", jak chciałbym, aby wyglądał jak one" two" three. Zauważ, że ostatnie trzy nie mają nawiasów. Jakieś pomysły?
oink

2
@oink, do którego możesz potokować wyniki, sed '$s/..$//'aby usunąć ostatnie 2 znaki z ostatniego wiersza.
Chris Seymour,

3
Jeśli chcesz zastąpić znaki nowej linii niczym, musisz użyć tej --deleteopcji, ponieważ domyślnie oczekuje dwóch argumentów. np tr --delete '\n'.
Elijah Lynn,

69

Wyjście potokiem do xargsspowoduje połączenie każdego wiersza wyjścia w jeden wiersz ze spacjami:

grep pattern file | xargs

Lub dowolne polecenie, np. ls | xargs. Domyślny limit xargswyjściowy to ~ 4096 znaków, ale można go zwiększyć np. xargs -s 8192.


| tr '\n' ' 'nie działał dla mnie, gdy został wywołany przez php execfunkcję. Ignorował tr i dawał tylko ostatni mecz od grepa. | xargspracował.
Adarsha

3
To rozwiązanie ma również tę zaletę, że „zjada” przestrzenie z wejścia. +1
Rene,

55

W bash echobez cudzysłowów usuń powrót karetki, tabulatory i wiele spacji

echo $(cat file)

8
Bardzo niedoceniana odpowiedź tutaj, jest naprawdę prosta i działa jak urok, z końcowym znakiem nowej linii.
Dangercrow,

Jest to szczególnie IFS="$(printf '\n\t')"
fajne,

5
Lub po prostu echo $(<file)... używanie echa jest nie tylko ładniejsze niż używanie tr '\n' ' ', ale także lepsze (pomyśl o \r\nzakończeniach linii). @aggsol, możesz po prostu powiedziećIFS=$'\n\t'
Normadize

A może bez miejsca?
DimiDak

22

To może być to, czego chcesz

cat file | grep pattern | paste -sd' '

Co do twojej edycji, nie jestem pewien, co to oznacza, może to?

cat file | grep pattern | paste -sd'~' | sed -e 's/~/" "/g'

(przy założeniu, że ~nie występuje w file)


2
@Stephan nie było potrzeby zakładać, że cat filefaktycznie będzie cat, a nawet plik. (I właśnie opuścił część niezmieniona, jak to było bez znaczenia dla kwestii)
sehe

5

To jest przykład, który generuje dane wyjściowe oddzielone przecinkami. Możesz zastąpić przecinek dowolnym separatorem, którego potrzebujesz.

cat <<EOD | xargs | sed 's/ /,/g'
> 1
> 2
> 3
> 4
> 5
> EOD

produkuje:

1,2,3,4,5

3

Oto metoda wykorzystująca exedytor (część Vima ):

  • J oin wszystkich liniach i p RINT do standardowe wyjście

    $ ex +%j +%p -scq! file
  • J oin linie w miejscu (w pliku):

    $ ex +%j -scwq file

    Uwaga: Spowoduje to konkatenację wszystkich wierszy wewnątrz pliku!


2

Najszybsze i najłatwiejsze sposoby rozwiązania tego problemu, jakie znam:

Kiedy chcemy zastąpić znak nowego wiersza \n spacją :

xargs < file

xargsma własne ograniczenia dotyczące liczby znaków w linii i liczby wszystkich znaków łącznie, ale możemy je zwiększyć. Szczegóły można znaleźć uruchamiając to polecenie: xargs --show-limitsi oczywiście w instrukcji:man xargs

Kiedy chcemy zamienić jeden znak na inny, dokładnie jeden znak :

tr '\n' ' ' < file

Gdy chcemy zamienić jeden znak na wiele znaków :

tr '\n' '~' < file | sed s/~/many_characters/g

Najpierw zamieniamy znaki nowej linii \nna tyldy ~(lub wybieramy inny unikalny znak nieobecny w tekście), a następnie zastępujemy znaki tyldy dowolnymi innymi znakami ( many_characters) i robimy to dla każdej tyldy (flagi g).


0

Prawdopodobnie najlepszym sposobem na to jest użycie narzędzia „awk”, które wygeneruje wynik w jednej linii

$ awk ' /pattern/ {print}' ORS=' ' /path/to/file

Spowoduje to scalenie wszystkich linii w jedną z ogranicznikiem spacji


Nie potrzebujesz, {print}ponieważ jest to domyślna akcja awk.
ostry

0

Oto kolejna prosta metoda wykorzystująca awk:

# cat > file.txt
a
b
c

# cat file.txt | awk '{ printf("%s ", $0) }'
a b c

Ponadto, jeśli plik zawiera kolumny, daje to łatwy sposób na konkatenację tylko niektórych kolumn:

# cat > cols.txt
a b c
d e f

# cat cols.txt | awk '{ printf("%s ", $2) }'
b e

-1

Na Linuksie Red Hat używam tylko echo:

echo $ (kot / jakiś / plik / nazwa)

To daje mi wszystkie rekordy pliku w jednej linii.


2
To już odpowiedź w 2015 roku. Powielasz tę odpowiedź . Przeczytaj odpowiedzi przed wysłaniem własnych, szczególnie gdy pytanie ma 7 lat i jest już 8 odpowiedzi.
Mickael B.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.