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.
(cd That/Directory ; cat file_{1..2000}.pdb >> file_all.pdb )
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 :
seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb
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
getconf ARG_MAX
xargs --show-limits
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ł go xargs
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
#!/bin/bash
StartN=${1:-1} # First file number
EndN=${2:-15000} # Last file number
BlockN=${3:-100} # files in a Block
OutFile=${4:-"all.pdb"} # Output file name
CurrentStart=$StartN
for i in $(seq $StartN $BlockN $EndN)
do
CurrentEnd=$i ;
cat $(seq -f file_%.17g.pdb $CurrentStart $CurrentEnd) >> $OutFile;
CurrentStart=$(( CurrentEnd + 1 ))
done
# Here you may need to do a last iteration for the part cut from seq
[[ $EndN -ge $CurrentStart ]] &&
cat $(seq -f file_%.17g.pdb $CurrentStart $EndN) >> $OutFile;
Wersja 2
Wywoływanie bash dla rozszerzenia (nieco wolniej w moich testach ~ 20%).
#!/bin/bash
StartN=${1:-1} # First file number
EndN=${2:-15000} # Last file number
BlockN=${3:-100} # files in a Block
OutFile=${4:-"all.pdb"} # Output file name
CurrentStart=$StartN
for i in $(seq $StartN $BlockN $EndN)
do
CurrentEnd=$i ;
echo cat file_{$CurrentStart..$CurrentEnd}.pdb | /bin/bash >> $OutFile;
CurrentStart=$(( CurrentEnd + 1 ))
done
# Here you may need to do a last iteration for the part cut from seq
[[ $EndN -ge $CurrentStart ]] &&
echo cat file_{$CurrentStart..$EndN}.pdb | /bin/bash >> $OutFile;
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 ] ...