Mam około 15000 plików o nazwach file_1.pdb
, file_2.pdb
itp mogę kot o kilka tysięcy z nich w kolejności wykonując:
cat file_{1..2000}.pdb >> file_all.pdb
Jeśli jednak zrobię to dla 15 000 plików, pojawi się błąd
-bash: /bin/cat: Argument list too long
Widziałem, jak ten problem został rozwiązany, find . -name xx -exec xx
ale nie zachowałoby to kolejności łączenia plików. Jak mogę to osiągnąć?
files
find
cat
brace-expansion
Azotan sodu
źródło
źródło
cat file_{1..15000}.pdb
konstrukcja działa dla mnie dobrze.getconf ARG_MAX
powinien powiedzieć.Odpowiedzi:
Korzystanie
find
,sort
ixargs
:find
Polecenie znajdzie wszystkie istotne pliki, a następnie wydrukowanie ich ścieżek sięsort
, że robi „wersji rodzaju”, aby uzyskać je w odpowiedniej kolejności (jeśli numery w nazwach było zero-wypełnione stałą szerokość nie byłby potrzebny-V
).xargs
pobiera tę listę posortowanych nazw ścieżek i uruchamiacat
je w tak dużych partiach, jak to możliwe.Powinno to działać, nawet jeśli nazwy plików zawierają dziwne znaki, takie jak znaki nowej linii i spacje. Używamy
-print0
zfind
do nadawaniasort
nazw zakończonych zerami do sortowania, isort
posługujemy się nimi za pomocą-z
.xargs
też odczytuje nazwy zakończone znakiem NUL ze swoją-0
flagą.Zauważ, że piszę wynik do pliku, którego nazwa nie pasuje do wzorca
file_*.pdb
.Powyższe rozwiązanie wykorzystuje niektóre niestandardowe flagi dla niektórych narzędzi. Są one obsługiwane przez implementację GNU tych narzędzi oraz przynajmniej przez OpenBSD i implementację macOS.
Stosowane są niestandardowe flagi
-maxdepth 1
, aby wprowadzićfind
tylko najwyższy katalog, ale nie podkatalogi. POSIXly, użyjfind . ! -name . -prune ...
-print0
, aby utworzyćfind
wyjściowe nazwy zakończone wartością zerową (było to rozważane przez POSIX, ale odrzucone). Można-exec printf '%s\0' {} +
zamiast tego użyć .-z
, aby robićsort
rekordy zakończone zerami. Brak równoważności POSIX.-V
, abysort
posortować np .200
po3
. Nie ma odpowiednika POSIX, ale można go zastąpić sortowaniem numerycznym w określonych częściach nazwy pliku, jeśli nazwy plików mają stały prefiks.-0
, aby dokonaćxargs
odczytu zapisów zakończonych zerami. Brak równoważności POSIX. POSIXly, należałoby zacytować nazwy plików w formacie rozpoznawanym przezxargs
.Jeśli ścieżki: są dobrze wychowane, a jeśli struktura katalogów jest płaska (bez podkatalogów), wówczas można by obejść się bez tych flag, z wyjątkiem
-V
zsort
.źródło
printf ‘file_%d.pdb\0’ {1..15000} | xargs -0 cat
, lub nawet z punktu Kevina,echo file_{1..15000}.pdb | xargs cat
.find
Rozwiązanie ma znacznie więcej napowietrznych ponieważ ma przeszukać system plików dla tych plików, ale jest bardziej przydatna, gdy niektóre pliki mogą nie istnieć.xargs
raczejcat
przekierowywane (każdecat
wywołanie będzie korzystało zexargs
standardowego wyjścia). Gdybyśmy powiedzieli,xargs -0 sh -c 'cat >all.pdb'
wtedy sensowniej byłoby użyć>>
zamiast tego>
, jeśli o to ci chodzi.sort -n -k1.6
że działałoby (dla oryginału,file_nnn
nazw plików lubsort -n -k1.5
dla tych bez podkreślenia).Z
zsh
(skąd{1..15000}
pochodzi ten operator):Lub dla wszystkich
file_<digits>.pdb
plików w kolejności numerycznej:(gdzie
<x-y>
jest operatorem globalnym, który dopasowuje liczby dziesiętne x do y. Bez,x
aniy
żadna liczba dziesiętna. Równoważna doextendedglob
's[0-9]##
lubkshglob
'+([0-9])
(jedna lub więcej cyfr)).Za
ksh93
pomocą wbudowanegocat
polecenia (więc nie ma wpływu na limitexecve()
wywołania systemowego, ponieważ nie ma wykonania ):Z
bash
/zsh
/ksh93
(których wsparciezsh
jest{x..y}
i mająprintf
wbudowane):W systemie GNU lub zgodnym możesz również użyć
seq
:W przypadku
xargs
rozwiązań opartych na rozwiązaniach specjalnych należy zachować szczególną ostrożność w przypadku nazw plików zawierających spacje, pojedyncze lub podwójne cudzysłowy lub odwrotne ukośniki.Jak dla
-It's a trickier filename - 12.pdb
, użyj:źródło
seq -f | xarg cat >
najbardziej eleganckie i skuteczne rozwiązanie. (MOIM ZDANIEM).'"./-It'\''s a trickier filename - %.17g.pdb"'
?Pętla for jest możliwa i bardzo prosta.
Minusem jest to, że wywołujesz
cat
piekło wiele razy. Ale jeśli nie pamiętasz dokładnie, jak to zrobić,find
a koszt wywołania nie jest taki zły w twojej sytuacji, warto o tym pamiętać.źródło
echo $i;
w treści pętli jako „wskaźnik postępu”źródło
seq -f file_%.10g.pdb 15000
. Zauważ, żeseq
to nie jest standardowe polecenie.seq -f
to świetny sposób, aby to zrobić; zapamięta to.Przesłanka
Nie powinieneś ponosić tego błędu tylko dla 15k plików o tym formacie nazw [ 1 , 2 ] .
Jeśli używasz tego rozszerzenia z innego katalogu i musisz dodać ścieżkę do każdego pliku, rozmiar twojego polecenia będzie większy i oczywiście może się zdarzyć.
Rozwiązanie uruchom komendę z tego katalogu.
Najlepsze rozwiązanie Jeśli zamiast tego zgadłem źle i uruchomisz go z katalogu, w którym znajdują się pliki ...
IMHO najlepszym rozwiązaniem są te Stéphane Chazelas :
z printf lub seq; przetestowany na 15k plików z tylko ich liczbą w pamięci podręcznej, jest nawet szybszy (obecnie i oprócz OP z tego samego katalogu, w którym znajdują się pliki).
Jeszcze kilka słów
Powinieneś być w stanie przejść do linii poleceń powłoki dłużej.
Twój wiersz poleceń ma 213914 znaków i zawiera 15003 słów
cat file_{1..15000}.pdb " > file_all.pdb" | wc
... nawet dodanie 8 bajtów dla każdego słowa to 333 938 bajtów (0,3 M) znacznie poniżej 2097142 (2,1 M) zgłoszonych przez
ARG_MAX
jądro 3.13.0 lub nieco mniejszy 2088232 zgłoszony jako „Maksymalna długość polecenia, którą moglibyśmy faktycznie użyj „ przezxargs --show-limits
Spójrz na swój system na wyjście
Lenistyczne rozwiązanie kierowane
W takich przypadkach wolę pracować z blokami, nawet jeśli zwykle wychodzi to na czas.
Logika (jeśli w ogóle) jest taka, że jestem zbyt leniwy, aby napisać 1 ... 1000 1001..2000 itd. Itd.
Więc proszę skrypt, aby to dla mnie zrobił.
Dopiero po sprawdzeniu poprawności danych wyjściowych przekierowuję je do skryptu.
... ale lenistwo jest stanem umysłu .
Ponieważ jestem uczulony na
xargs
(naprawdę powinienem był goxargs
tutaj użyć ) i nie chcę sprawdzać, jak z niego korzystać, punktualnie kończę, aby wymyślić koło ponownie, jak w poniższych przykładach (tl; dr).Zwróć uwagę, że ponieważ nazwy plików są kontrolowane (bez spacji, znaków nowej linii ...), możesz łatwo przejść z czymś w rodzaju skryptu poniżej.
tl; dr
Wersja 1: przekazuje jako parametr opcjonalny 1. numer pliku, ostatni, rozmiar bloku, plik wyjściowy
Wersja 2
Wywoływanie bash dla rozszerzenia (nieco wolniej w moich testach ~ 20%).
Oczywiście możesz iść do przodu i całkowicie pozbyć się
seq
[ 3 ] (z coreutils) i pracować bezpośrednio ze zmiennymi w bash, lub użyć Pythona lub skompilować program ac, aby to zrobić [ 4 ] ...źródło
%g
to skrót%.6g
. Oznaczałoby to na przykład 1 000 000 jako 1e + 06.xargs
, zshzargs
lubksh93
'scommand -x
.seq
to nie jest wbudowane bash, to polecenie z jądra GNU.seq -f %g 1000000 1000000
wyprowadza 1e + 06 nawet w najnowszej wersji coreutils.xarg
... ale rozumiem, że jest to sprawa osobista i być może związana tylko ze mną.Innym sposobem na to może być
źródło