Dlaczego to nie działa? „Ls * .txt | xargs cat> all.txt ”(wszystkie pliki w jednym dokumencie txt)

20

Dlaczego to nie działa?

ls *.txt | xargs cat > all.txt

(Chcę połączyć zawartość wszystkich plików tekstowych w pojedynczy plik „all.txt”). Find z -exec powinien również działać, ale naprawdę chciałbym zrozumieć składnię xargs.

Dzięki

ajo
źródło
1
Chociaż nie używaj lsdo tego . Jeśli naprawdę nie możesz użyć, cat *.txt >all.txtspróbuj, printf '%s\0' *.txt | xargs -r0 cat >alla następnie mv all all.txtunikaj odwoływania się do pliku.
tripleee

Odpowiedzi:

27

ls *.txt | xargs cat >> all.txt

może działać nieco lepiej, ponieważ dołączałby do pliku all.txt zamiast tworzyć go ponownie po każdym pliku.

Nawiasem mówiąc, cat *.txt >all.txtdziałałoby również. :-)

Janne Pikkarainen
źródło
6
Cat * .txt> all.txt jest oczywiście lepszy. Dzięki
ajo
1
Jednak ... | xargs cat >> all.txt lub> all.txt zawsze zwracają błąd z xargs: niedopasowany pojedynczy cudzysłów ... Czy to dlatego, że xargs bierze wszystko za nim jako polecenie?
ajo
1
Czy masz nazwy plików ze spacjami? Jeśli tak, użyj zamiast tego czegoś w rodzaju „znajdź / twoja / ścieżka -nazwa” * .txt '-print0 | xargs -0 cat >> all.txt ”
Janne Pikkarainen
1
nie, zastąpiłem wszystkie spacje plików . Ale myśląc o tym, niektóre nazwy plików mogą zawierać pojedyncze cudzysłowy, ponieważ w listing_O'Connor .txt może to być problem!
ajo
Tak, to jest problem. :) Najłatwiejszym i najrozsądniejszym sposobem jest użycie find z -print0 w połączeniu z xargs -0 - wtedy cały łańcuch użyje znaku NULL jako separatora i białych znaków, a znaki specjalne będą obsługiwane automatycznie.
Janne Pikkarainen
3

Jeśli niektóre nazwy plików zawierają „,” lub spacja xargsnie powiedzie się z powodu problemu z separatorem

Zasadniczo nigdy nie biegnij xargsbez -0, ponieważ wróci i cię ugryzie.

Zamiast tego rozważ użycie GNU Parallel:

ls *.txt | parallel cat > tmp/all.txt

lub jeśli wolisz:

ls *.txt | parallel cat >> tmp/all.txt

Dowiedz się więcej o GNU Parallel http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
źródło
1

all.txt jest plikiem w tym samym katalogu, więc cat jest zdezorientowany, gdy chce pisać z tego samego pliku do tego samego pliku.

Z drugiej strony:

ls *.txt | xargs cat > tmp/all.txt

Spowoduje to odczytanie plików tekstowych z bieżącego katalogu do pliku all.txt w podkatalogu (nie jest dołączony *.txt).

Jeremy Smyth
źródło
Nadal występuje następujący błąd: xargs: niedopasowany pojedynczy cytat; domyślnie cytaty są specjalne dla xargs, chyba że użyjesz opcji -0
ajo
1
Czy masz plik .txt z pojedynczym cytatem w nazwie?
Jeremy Smyth,
0

Możesz także natknąć się na ograniczenie długości linii poleceń. Jednym z powodów użycia xargsjest to, że dzieli dane wejściowe na bezpieczne fragmenty wielkości wiersza polecenia. Wyobraź sobie więc sytuację, w której masz w katalogu setki tysięcy plików .txt. ls *.txtzawiedzie. Musisz to zrobić

ls | grep .txt$ |xargs cat > /some/other/path/all.txt

.txt$w tym przypadku jest wyrażenie regularne pasujące do wszystkiego, co kończy się na .txt (więc nie jest dokładnie tak *.txt, ponieważ jeśli masz plik o nazwie atxt, to *.txtnie pasuje do niego, ale wyrażenie regularne tak.)

Zastosowanie innej ścieżki polega na tym, że, jak wskazały inne odpowiedzi, plik all.txt jest dopasowywany do wzorca, *.txtco spowodowałoby konflikt między danymi wejściowymi i wyjściowymi.

Pamiętaj, że jeśli masz 'w nazwie jakieś pliki (i może to być przyczyną unmatched single quotebłędu), powinieneś to zrobić

ls | grep --null .txt$ | xargs -0 cat > /some/other/path/all.txt

Opcja --null mówi grepowi, aby używał danych wyjściowych oddzielonych znakiem \0(aka null) zamiast domyślnego znaku nowej linii, a -0opcja `xargs mówi, że oczekuje wejścia w tym samym formacie. Działa to nawet, jeśli masz nazwy plików z nowymi liniami.

Brian Minton
źródło