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.

T. Webster
źródło
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
podobne do „ stackoverflow.com/questions/2764051/…
Shervin Emami
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" 
Chris Seymour
źródło
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.

bluebadge
źródło
| 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)
user1699917
źródło
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)

sehe
źródło
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
Richard Gomes
źródło
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!

kenorb
źródło
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).

simhumileco
źródło
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

Vladimir Yahello
źródło
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
wstępni
źródło
-1

Na Linuksie Red Hat używam tylko echo:

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

To daje mi wszystkie rekordy pliku w jednej linii.

user13498546
źródło
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.