it-swarm.it

Il modo migliore per rimuovere i byte dall'inizio di un file?

Oggi ho dovuto rimuovere i primi 1131 byte da un file di testo/binario misto da 800 MB, un dump Subversion filtrato che sto hackerando per un nuovo repository. Qual'è il miglior modo per farlo?

Per cominciare, ho provato

dd bs=1 skip=1131 if=filtered.dump of=trimmed.dump

ma dopo il salto questo copia il resto del file un byte alla volta, cioè molto lentamente. Alla fine ho capito che avevo bisogno di 405 byte per arrotondare questo fino a tre blocchi di 512 che potevo saltare

dd if=/dev/zero of=405zeros bs=1 count=405
cat 405zeros filtered.dump | dd bs=512 skip=3 of=trimmed.dump

che è stato completato abbastanza rapidamente ma deve esserci stato un modo più semplice/migliore? C'è un altro strumento di cui mi sono dimenticato? Grazie!

64
Rup

Puoi cambiare bs e saltare le opzioni:

dd bs=1131 skip=1 if=filtered.dump of=trimmed.dump

In questo modo l'operazione può beneficiare di un blocco maggiore.

Altrimenti, potresti provare con tail (anche se non è sicuro usarlo con file binari):

tail -c +1132 filtered.dump >trimmed.dump

Infine, puoi usare 3 istanze dd per scrivere qualcosa del genere:

dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }

dove il primo dd stampa il suo output standard filtered.dump; il secondo legge solo 1131 byte e li butta via; quindi l'ultimo legge dal suo input standard i byte rimanenti di filtered.dump e li scrive in trimmed.dump.

67
marco

Non sono sicuro quando skip_bytes è stato aggiunto, ma per saltare i primi 11 byte hai:

# echo {123456789}-abcdefgh- | 
                              dd bs=4096 skip=11 iflag=skip_bytes
-abcdefgh-
0+1 records in
0+1 records out
11 bytes (11 B) copied, 6.963e-05 s, 158 kB/s

Dove iflag=skip_bytes dice a dd di interpretare il valore dell'opzione skip come byte anziché blocchi, rendendolo semplice.

Puoi usare una sotto-shell e due dd chiamate in questo modo:

$ ( dd bs=1131 count=1 of=dev_null && dd bs=4K of=out.mp3 ) < 100827_MR029_LobbyControl.mp3
1+0 records in
1+0 records out
1131 bytes (1.1 kB) copied, 7.9691e-05 s, 14.2 MB/s
22433+1 records in
22433+1 records out
91886130 bytes (92 MB) copied, 0.329823 s, 279 MB/s
$ ls -l *
-rw------- 1 max users 91887261 2011-02-03 22:59 100827_MR029_LobbyControl.mp3
-rw-r--r-- 1 max users     1131 2011-02-03 23:04 dev_null
-rw-r--r-- 1 max users 91886130 2011-02-03 23:04 out.mp3
$ cat dev_null out.mp3 > orig
$ cmp 100827_MR029_LobbyControl.mp3 orig
15
maxschlepzig

Se il filesystem e il kernel Linux lo supportano, allora potresti provare fallocate se vuoi apportare le modifiche sul posto: nel migliore dei casi non ci sono dati IO affatto:

$ fallocate <magic> -o 0 -l 1131 inplace.dump

dove <magic> dipende dal filesystem, dalla versione di Linux e dal tipo di file ( FALLOC_FL_COLLAPSE_RANGE o FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE potrebbe essere utilizzato internamente ).

7
jfs

Dovresti usare count=0 - questo è un semplice lseek() ogni volta che è possibile.

Come questo:

{  dd bs=1131 skip=1 count=0; cat; } <filtered.dump >trimmed.dump

dd eseguirà lseek() il descrittore del file di input in un offset di 1131 byte, quindi cat copierà semplicemente tutto ciò che rimane nell'output.

3
mikeserv

Un altro modo per rimuovere i byte iniziali da un file (senza usare dd) è usare rispettivamente xxd e sed o tail.

bytes=$((1131*2))

xxd -p -c 256 filtered.dump | tr -d '\n' | sed "s/^.\{0,${bytes}\}//" | xxd -r -p > trimmed.dump

bytes=$((bytes + 1)) 
xxd -p -c 256 filtered.dump | tr -d '\n' | tail -c +${bytes} | xxd -r -p > trimmed.dump
2
wop

@maxschlepzig chiede un liner online. Eccone uno in Perl. Prende 2 argomenti: da byte e lunghezza. Il file di input deve essere dato da '<' e l'output sarà su stdout:

Perl -e 'sysseek(STDIN,shift,0) || die; $left = shift;
     while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){
        $left -= $read; syswrite(STDOUT,$buf);
     }' 12345678901 19876543212 < bigfile > outfile

Se la lunghezza è maggiore del file, il resto del file verrà copiato.

Sul mio sistema questo fornisce 3,5 GB/s.

2
Ole Tange