Premessa
Non dovresti incorrere in questo errore solo per 15k file con quel formato di nome specifico [ 1 , 2 ] .
Se stai eseguendo tale espansione da un'altra directory e devi aggiungere il percorso a ciascun file, la dimensione del tuo comando sarà più grande e, naturalmente, può verificarsi.
La soluzione esegue il comando da quella directory.
(cd That/Directory ; cat file_{1..2000}.pdb >> file_all.pdb )
La migliore soluzione Se invece ho indovinato e lo esegui dalla directory in cui sono i file ...
IMHO la soluzione migliore è quella di Stéphane Chazelas :
seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb
con printf o seq; testato su file 15k con solo il loro numero all'interno pre-memorizzato nella cache, è anche il più veloce (al momento e ad eccezione di quello OP dalla stessa directory in cui si trovano i file).
Qualche parola in più
Dovresti essere in grado di passare più a lungo alle righe di comando della shell.
La riga di comando è lunga 213914 caratteri e contiene 15003 parole
cat file_{1..15000}.pdb " > file_all.pdb" | wc
... anche l'aggiunta di 8 byte per ogni parola è di 333 938 byte (0,3 M) molto al di sotto del 2097142 (2,1 M) riportato da ARG_MAX
un kernel 3.13.0 o del 2088232 leggermente più piccolo riportato come "Lunghezza massima del comando che potremmo effettivamente usa " dixargs --show-limits
Dai un'occhiata al tuo sistema all'output di
getconf ARG_MAX
xargs --show-limits
Soluzione guidata per pigrizia
In casi come questo preferisco lavorare con i blocchi anche perché di solito viene fuori una soluzione efficiente in termini di tempo.
La logica (se presente) è che sono troppo pigro per scrivere 1 ... 1000 1001..2000 ecc ecc ...
Quindi chiedo a uno script di farlo per me.
Solo dopo aver verificato che l'output è corretto, lo reindirizzo a uno script.
... ma la pigrizia è uno stato d'animo .
Dato che sono allergico a xargs
(avrei dovuto usarlo xargs
qui) e non voglio controllare come usarlo, finisco puntualmente di reinventare la ruota come negli esempi seguenti (tl; dr).
Si noti che poiché i nomi dei file sono controllati (senza spazi, newline ...) puoi andare facilmente con qualcosa come lo script qui sotto.
tl; dr
Versione 1: passa come parametro opzionale il primo numero di file, l'ultimo, la dimensione del blocco, il file di output
#!/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;
Versione 2
Chiamando bash per l'espansione (un po 'più lento nei miei test ~ 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;
Ovviamente puoi andare avanti e liberarti completamente di seq
[ 3 ] (da coreutils) e lavorare direttamente con le variabili in bash, oppure usare python o compilare un programma ac per farlo [ 4 ] ...