2011-11-09 15 views
16

Mam plik binarny, który konwertuję do zwykłego pliku przy użyciu hexdump i kilku poleceń awk i sed. Plik wyjściowy wygląda mniej więcej tak -Podziel jeden plik na wiele plików na podstawie wzorca

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

plik temp ma kilka łapacze oczu (3d3d), które nie powtarzać tak często. W pewnym sensie oznaczają początek nowego rekordu binarnego. Muszę podzielić plik na podstawie tych przyciągających wzrok.

Moim pożądanym wynikiem jest posiadanie wielu plików (w oparciu o liczbę obserwatorów w moim pliku tymczasowym).

Więc moje wyjście będzie wyglądać mniej więcej tak -

$cat temp1 
3d3d01f87347545002f1d5b2be4ee4d700010100018000cc57e582000000000000000 
0000000000087d3f513000000000000000000000000000000000001001001010f00000000 
002658783100b354c52658783100b4 

$cat temp2 
3d3d0000ad6413400103231665f301010b9130194899f2ffffffffffff02007c00dc0 
15800a040402802f1d5b2b8ca5674504f4330310000000000046363070000000000000000 
000000000065450000b4fb6b400039 

$cat temp3 
3d3d1116cdcc57e58287d3f55285a1084b 

Odpowiedz

14
#!/usr/bin/perl 

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

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

Dzięki to działa świetnie i mogę nazwać tego skryptu w moim skrypcie parsera przed uruchomieniem kodu parsera tak, że działa na wszystkich plików tymczasowych . –

+0

Wszelkie sugestie dotyczące książki, które należy zgłosić do nauki Perl. Jestem nowy w UNIX i zacząłem ostatnio uczyć się bash, sed i awk. –

+3

Prawdopodobnie * [Perl uczący] (http://www.amazon.com/dp/1449303587) *. –

-1

To zależy, czy jest to pojedynczy wiersz w pliku temp czy nie. Ale zakładając, że jeśli jest to pojedyncza linia, można przejść z:

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

Pierwsze sed wstawia # jako separator pola/pozycję, a następnie awk Dzieli on # i drukuje każdy „pole” do własnego pliku.

Jeśli plik wejściowy jest już podzielony na 3d3d następnie można przejść z:

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

HTH

5

Może to działa:

# 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:

Jeśli istnieje są nowe linie w pliku źródłowym, które możesz usunąć najpierw za pomocą tr -d '\n' <temp, a następnie potnij wyjście przez powyższe polecenie sed. Jeśli jednak chcesz zachować je wtedy:

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

powinno wystarczyć

16

RS zmienna w awk jest miłe dla tego, co pozwala ustawić separator rekordu. W związku z tym wystarczy przechwycić każdy rekord we własnym pliku tymczasowym. Najprostsza wersja to:

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

Próbka tekst zaczyna się od przyciąga wzrok 3d3d, więc temp1 będzie pusty plik. Co więcej, sam przyciągający wzrok nie będzie na początku plików tymczasowych, jak pokazano dla plików tymczasowych w pytaniu. Na koniec, jeśli istnieje wiele rekordów, można uruchomić limit systemu na otwarte pliki. Pewne drobne komplikacje przyniesie go bliżej, co chcesz i uczynić go bezpieczniejszym:

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

Khm, ty don do tego potrzebuję "kota". A jeśli jest to pojedyncze wejście liniowe, otrzymasz tylko pierwszy rekord. A wynik również nie obejdzie oryginalnego 'RS'. 'echo '3d3dsomething3d3daniething' | awk 'BEGIN {RS = "3d3d"} {print}' 'wypisze tylko' coś'. –

+1

Albo się myliłem. Jedynym problemem z twoim rozwiązaniem jest brak 'RS' na wyjściu. (I bezużyteczne użycie 'cat'.) –

+2

@ZsoltBotykai RS jest na wyjściu, jak to omówiono. A kot nie jest bezużyteczny: zapewnia logiczną separację między generowaniem danych a przetwarzaniem. Tak więc 'cat temp' oznacza wszelkie transformacje zachodzące przed etapem awk, unikając dodawania jeszcze więcej do już długiej linii za pomocą awk. –

Powiązane problemy