Mam ± 10 000 plików ( res.1
- res.10000
), wszystkie składające się z jednej kolumny i równej liczby wierszy. To, czego chcę, jest w gruncie rzeczy proste; scal wszystkie pliki kolumnowo w nowy plik final.res
. Próbowałem użyć:
paste res.*
Jednak (choć to wydaje się działać dla małego podzbioru plików wynikowych, to daje następujący błąd, gdy wykonywane na całym zbiorze: Too many open files
.
Musi istnieć „łatwy” sposób, aby to zrobić, ale niestety jestem całkiem nowy w Uniksie. Z góry dziękuję!
PS: Aby dać Ci wyobrażenie o tym, jak wygląda (jeden z moich) plików danych:
0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...
--serial
opcji zpaste
poleceniem?paste --serial
nie łączy plików w kolumnach ...paste -s
rzeczywiście działa, ale wkleja osobne pliki wyników wierszami zamiast kolumnami. Jest to jednak coś, co mogę rozwiązać. Dzięki!Odpowiedzi:
Jeśli masz uprawnienia roota na tym komputerze, możesz tymczasowo zwiększyć limit „maksymalnej liczby otwartych deskryptorów plików”:
I wtedy
Następnie możesz przywrócić oryginalne wartości.
Drugie rozwiązanie , jeśli nie można zmienić limit:
Wzywa
paste
do każdego pliku jeden raz, a na końcu jest ogromny plik ze wszystkimi kolumnami (zajmuje to chwilę).Edycja : Bezużyteczne użycie kota ... Nie !
Jak wspomniano w komentarzach, użycie funkcji
cat
here (cat final.res | paste - $f >temp
) nie jest bezużyteczne. Przy pierwszym uruchomieniu pętli plik jeszczefinal.res
nie istnieje.paste
wtedy się nie powiedzie i plik nie zostanie nigdy wypełniony ani utworzony. Moje rozwiązaniecat
kończy się niepowodzeniem tylko za pierwszym razemNo such file or directory
ipaste
odczytuje ze standardowego pustego pliku, ale kontynuuje. Błąd można zignorować.źródło
ulimit -Sn
dla miękkiego limitu iulimit -Hn
dla twardego limitu-bash: /usr/bin/paste: Argument list too long
. Pomysły, jak to rozwiązać? Przepraszam, że przeszkadzam.getconf ARG_MAX
, możesz zwiększyć tę wartość tylko podczas ponownej kompilacji jądra. Możesz wypróbować moje drugie rozwiązanie?cat
każdym razem pętli, możesz zacząć od utworzenia pustegofinal.res
pliku. Jest to prawdopodobnie dobry pomysł, na wypadek, gdybyfinal.res
plik już tam był.Jeśli odpowiedź chaosu nie ma zastosowania (ponieważ nie masz wymaganych uprawnień), możesz grupować
paste
połączenia w następujący sposób:Lista plików 1000 naraz w plikach o nazwach
lists00
,lists01
itp, a następnie wklejenie odpowiednichres.
plików do plików o nazwachmerge00
,merge01
itp, a na końcu łączy wszystkie wynikające częściowo połączone pliki.Jak wspomniano w chaosie , możesz zwiększyć liczbę plików używanych jednocześnie; limit to podana wartość
ulimit -n
minus jak wiele plików już masz, tak byś powiedziałużyć limitu minus dziesięć.
Jeśli twoja wersja
split
nie obsługuje-d
, możesz ją usunąć: wystarczysplit
użyć sufiksów numerycznych. Domyślnie przyrostków będzieaa
,ab
itd., A nie01
,02
itd.Jeśli jest tak wiele plików, które
ls -1 res.*
zawodzą („zbyt długa lista argumentów”), możesz ją zastąpić,find
aby uniknąć tego błędu:(Jak zauważył don_crissti ,
-1
nie powinno to być konieczne przyls
wyjściu potoku ; pozostawiam to jednak do obsługi przypadków, w którychls
jest alias-C
).źródło
Spróbuj wykonać to w ten sposób:
Możesz także podzielić partię na części i wypróbować coś takiego:
i na koniec połącz pliki końcowe
źródło
Too many open files
final.x00
potoków be - jako nazwanych FIFO lub pośrednio, stosując podstawianie procesów (jeśli twoja powłoka je obsługuje - np. Bash). Pisanie ręczne nie jest fajne, ale może pasować do makefile.Nie wydaje mi się, żeby było to tak skomplikowane - wykonałeś już ciężką pracę, zamawiając nazwy plików. Tylko nie otwieraj ich wszystkich jednocześnie, to wszystko.
Inny sposób:
... ale myślę, że robi to wstecz ... To może działać lepiej:
A oto jeszcze jeden sposób:
Pozwala
tar
to zebrać wszystkie pliki w strumieniu rozdzielanym zerami, analizuje wszystkie metadane nagłówka oprócz nazwy pliku i przekształca wszystkie wiersze we wszystkich plikach w tabulatory. Opiera się jednak na tym, że dane wejściowe są rzeczywistymi plikami tekstowymi - co oznacza, że każdy kończy się na nowej linii i nie ma w bajtach pustych. Aha - i to również opiera się na nazwach będących nowalinia same wolne (choć które mogą być obsługiwane solidnie z GNUtar
„s--xform
opcja) . Biorąc pod uwagę, że te warunki są spełnione, powinien bardzo szybko pracować z dowolną liczbą plików - itar
wykona prawie wszystkie.Wynikiem jest zestaw linii, które wyglądają następująco:
I tak dalej.
Przetestowałem to, tworząc najpierw 5 plików testowych. Tak naprawdę nie miałem ochoty na generowanie 10000 plików, więc po prostu zwiększyłem trochę dla każdego z nich - i upewniłem się, że długości plików różnią się znacznie. Jest to ważne podczas testowania
tar
skryptów, ponieważtar
blokuje wejście do ustalonych długości - jeśli nie spróbujesz przynajmniej kilku różnych długości, nigdy nie dowiesz się, czy faktycznie poradzisz sobie tylko z jedną.W każdym razie dla plików testowych zrobiłem:
ls
później zgłoszono:... wtedy pobiegłem ...
... aby wyświetlić tylko pierwsze 25 pól rozdzielanych tabulatorami w linii (ponieważ każdy plik jest pojedynczą linią - jest ich dużo ) ...
Wynik był:
źródło
Biorąc pod uwagę liczbę plików, rozmiary linii itp., Myślę, że przewyższy domyślne rozmiary narzędzi (awk, sed, wklej, * itp.)
Stworzyłbym do tego mały program, nie miałby ani 10 000 otwartych plików, ani linii o długości setek tysięcy (10 000 plików po 10 (maksymalny rozmiar linii w przykładzie)). Wymaga tylko około 10 000 tablic liczb całkowitych, aby zapisać liczbę bajtów odczytanych z każdego pliku. Wadą jest to, że ma tylko jeden deskryptor pliku, jest ponownie wykorzystywany dla każdego pliku, dla każdej linii, a to może być powolne.
Definicje
FILES
iROWS
powinny zostać zmienione na rzeczywiste dokładne wartości. Dane wyjściowe są wysyłane do standardowego wyjścia.źródło