2011-11-09 15 views
16

Ho un file binario, che converto in un file normale utilizzando hexdump e pochi awk e sed comandi. Il file di output è simile al seguente:dividere un file in più file basati sul modello

$cat temp 
3d3d01f87347545002f1d5b2be4ee4d700010100018000cc57e5820000000000000000000 
000000087d3f513000000000000000000000000000000000001001001010f000000000026 
58783100b354c52658783100b43d3d0000ad6413400103231665f301010b9130194899f2f 
fffffffffff02007c00dc015800a040402802f1d5b2b8ca5674504f433031000000000004 
6363070000000000000000000000000065450000b4fb6b4000393d3d1116cdcc57e58287d 
3f55285a1084b 

Il file temporaneo ha alcuni accorgimenti (3d3d) che non si ripetono spesso. Dicono un inizio di nuovo record binario. Ho bisogno di dividere il file sulla base di quelli che attirano l'attenzione.

mio output desiderato è quello di avere più file (in base al numero di eyecatchers nel mio file temp).

Quindi la mia uscita sarebbe simile a questa -

$cat temp1 
3d3d01f87347545002f1d5b2be4ee4d700010100018000cc57e582000000000000000 
0000000000087d3f513000000000000000000000000000000000001001001010f00000000 
002658783100b354c52658783100b4 

$cat temp2 
3d3d0000ad6413400103231665f301010b9130194899f2ffffffffffff02007c00dc0 
15800a040402802f1d5b2b8ca5674504f4330310000000000046363070000000000000000 
000000000065450000b4fb6b400039 

$cat temp3 
3d3d1116cdcc57e58287d3f55285a1084b 

risposta

14
#!/usr/bin/perl 

undef $/; 
$_ = <>; 
$n = 0; 

for $match (split(/(?=3d3d)/)) { 
     open(O, '>temp' . ++$n); 
     print O $match; 
     close(O); 
} 
+0

Grazie questa grande opera e posso chiamare questo script nel mio script di parser prima di eseguire il codice di parser in modo che venga eseguito su tutti i file temporanei . –

+0

qualche suggerimento su quale libro dovrei prendere per imparare il Perl. Sono nuovo di UNIX e ho recentemente iniziato a imparare bash, sed e awk. –

+3

Probabilmente * [Learning Perl] (http://www.amazon.com/dp/1449303587) *. –

-1

Dipende se si tratta di una sola riga nel file temp o meno. Ma supponendo che se si tratta di una singola linea, si può andare con:

sed 's/\(.\)\(3d3d\)/\1#\2/g' FILE | awk -F "#" '{ for (i=1; i++; i<=NF) { print $i > "temp" i } }' 

I primi sed inserti un # come separatore di campo/record, awk spaccature su # e stampa ogni "campo" per un proprio file.

Se il file di input è già divisa su 3d3d allora si può andare con:

awk '/^3d3d/ { i++ } { print > "temp" i }' temp 

HTH

5

Questo potrebbe funzionare:

# sed 's/3d3d/\n&/2g' temp | split -dl1 - temp 
# ls 
temp temp00 temp01 temp02 
# cat temp00 
3d3d01f87347545002f1d5b2be4ee4d700010100018000cc57e5820000000000000000000000000087d3f513000000000000000000000000000000000001001001010f000000000026 58783100b354c52658783100b4 
# cat temp01 
3d3d0000ad6413400103231665f301010b9130194899f2ffffffffffff02007c00dc015800a040402802f1d5b2b8ca5674504f4330310000000000046363070000000000000000000000000065450000b4fb6b400039 
# cat temp02 
3d3d1116cdcc57e58287d3f55285a1084b 

EDIT:

Se c'è sono newline nel file sorgente che puoi rimuovere prima usando tr -d '\n' <temp e quindi il tubo di uscita attraverso il comando sopra sed. Se invece si desidera conservare loro poi:

sed 's/3d3d/\n&/g;s/^\n\(3d3d\)/\1/' temp |csplit -zf temp - '/^3d3d/' {*} 

dovrebbe fare il trucco

16

La variabile RS in awk è bello per questo, che consente di definire il separatore di record. Quindi, è sufficiente catturare ogni record nel proprio file temporaneo. La versione più semplice è:

testo
cat temp | 
    awk -v RS="3d3d" '{ print $0 > "temp" NR }' 

Il campione inizia con l'eye-catcher 3d3d, così temp1 sarà un file vuoto. Inoltre, lo stesso eye-catcher non sarà all'inizio dei file temporanei, come è stato mostrato per i file temporanei nella domanda. Infine, se ci sono molti record, potresti eseguire il limite di sistema sui file aperti. Alcune complicanze minori porteranno più vicino a ciò che si desidera e renderla più sicura:

cat temp | 
    awk -v RS="3d3d" 'NR > 1 { print RS $0 > "temp" (NR-1); close("temp" (NR-1)) }' 
+1

Khm, tu don Non ho bisogno di 'cat' per quello. E se si tratta di un ingresso a linea singola, otterrai solo il primo record. E l'uscita mancherà anche l'originale 'RS'. 'echo '3d3dsomething3d3danything' | awk 'BEGIN {RS = "3d3d"} {print}' 'produrrà solo' qualcosa'. –

+1

Oppure mi sbagliavo. L'unico problema con la tua soluzione manca il 'RS' nell'output. (E l'uso inutile di 'cat'.) –

+2

@ ZsoltBotykai RS è nell'output, come discusso. E il gatto non è inutile: fornisce una separazione logica tra la generazione di dati e l'elaborazione. Pertanto, 'cat temp' sostituisce tutte le trasformazioni che si verificano prima dello stage di awk, evitando di aggiungere ancora di più alla già lunga linea con awk. –

Problemi correlati