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 xargs
nel caso in cui la lunghezza della riga di comando superi ARG_MAX
e 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
find
viene 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).
bash
glob. Altrimenti non vedo alcun caso in cui xargs
o cat
non si comporterebbe come previsto.
xargs
chiamerà 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=always
il 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 ( python
o 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
è 0
per l' <>
operatore ( <>
è l'abbreviazione di 0<>
, come <
è l'abbreviazione di 0<
e >
abbreviazione di 1>
), quindi è necessario 1
reindirizzare 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.
dd
o tramite lettura.
fallocate
si annullerà il sovraccarico dell'extra find
, anche se sarà più veloce la seconda volta. btrfs
certamente apre alcune interessanti possibilità però.
find
non ordina i file allo stesso modo di una shell glob.