Ho 10k + file per un totale di oltre 20 GB che devo concatenare in un unico file.
C'è un modo più veloce di
cat input_file* >> out
?
Il modo preferito sarebbe un comando bash, anche Python è accettabile se non notevolmente più lento.
Ho 10k + file per un totale di oltre 20 GB che devo concatenare in un unico file.
C'è un modo più veloce di
cat input_file* >> out
?
Il modo preferito sarebbe un comando bash, anche Python è accettabile se non notevolmente più lento.
Risposte:
No, il gatto è sicuramente il modo migliore per farlo. Perché usare Python quando esiste un programma già scritto in C per questo scopo? Tuttavia, è possibile che si desideri prendere in considerazione l'utilizzo xargsnel caso in cui la lunghezza della riga di comando superi ARG_MAXe ne occorra più di una cat. Usando gli strumenti GNU, questo equivale a quello che hai già:
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z |
xargs -0 cat -- >>out
findviene reindirizzato sort. Senza questo, i file sarebbero elencati in un ordine arbitrario (definito dal file system, che potrebbe essere un ordine di creazione dei file).
bashglob. Altrimenti non vedo alcun caso in cui xargso catnon si comporterebbe come previsto.
xargschiamerà come catè necessario per evitare un errore E2BIG di execve (2).
Allocare prima lo spazio per il file di output può migliorare la velocità complessiva poiché il sistema non dovrà aggiornare l'allocazione per ogni scrittura.
Ad esempio, se su Linux:
size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z | xargs -r0 cat 1<> out
Un altro vantaggio è che se non c'è abbastanza spazio libero, la copia non verrà tentata.
Se questa opzione btrfsè attivata, è possibile utilizzare copy --reflink=alwaysil primo file (che non implica la copia dei dati e sarebbe quindi quasi istantaneo) e aggiungere il resto. Se ci sono 10000 file, probabilmente non farà molta differenza, a meno che il primo file non sia molto grande.
C'è un'API per generalizzare che per ricopiare tutti i file (il BTRFS_IOC_CLONE_RANGE ioctl), ma non sono riuscito a trovare alcuna utilità che esponga tale API, quindi dovresti farlo in C ( pythono in altre lingue purché possano chiamare arbitrari ioctl) .
Se i file di origine sono sparsi o hanno grandi sequenze di caratteri NUL, è possibile creare un file di output sparse (risparmiando tempo e spazio su disco) con (su sistemi GNU):
find . -maxdepth 1 -type f -name 'input_file*' -print0 |
sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
>né >>, ma 1<>come ho detto di scrivere nel file.
<>è l'operatore di reindirizzamento read + write standard Bourne / POSIX. Per i dettagli, consultare il manuale della shell o le specifiche POSIX . L'impostazione predefinita fdè 0per l' <>operatore ( <>è l'abbreviazione di 0<>, come <è l'abbreviazione di 0<e >abbreviazione di 1>), quindi è necessario 1reindirizzare esplicitamente stdout. Qui, non è così tanto che abbiamo bisogno di read + write ( O_RDWR), ma che non vogliamo O_TRUNC(come in >) che possa deallocare ciò che abbiamo appena assegnato.
ddo tramite lettura.
fallocatesi annullerà il sovraccarico dell'extra find, anche se sarà più veloce la seconda volta. btrfscertamente apre alcune interessanti possibilità però.
findnon ordina i file allo stesso modo di una shell glob.