2011-11-09 39 views
16

Tôi có tệp nhị phân mà tôi chuyển đổi thành tệp thông thường bằng cách sử dụng lệnh hexdump và vài lệnh awk và sed. Tệp đầu ra trông giống như thế này -Tách một tệp thành nhiều tệp dựa trên mẫu

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

Tệp tạm thời có ít người bắt mắt (3d3d) không lặp lại thường xuyên. Chúng thể hiện sự khởi đầu của bản ghi nhị phân mới. Tôi cần phải phân chia các tập tin dựa trên những người bắt mắt.

Kết quả mong muốn của tôi là có nhiều tệp (dựa trên số lượng mã vạch trong tệp tạm thời của tôi).

Vì vậy, đầu ra của tôi sẽ giống như thế này -

$cat temp1 
3d3d01f87347545002f1d5b2be4ee4d700010100018000cc57e582000000000000000 
0000000000087d3f513000000000000000000000000000000000001001001010f00000000 
002658783100b354c52658783100b4 

$cat temp2 
3d3d0000ad6413400103231665f301010b9130194899f2ffffffffffff02007c00dc0 
15800a040402802f1d5b2b8ca5674504f4330310000000000046363070000000000000000 
000000000065450000b4fb6b400039 

$cat temp3 
3d3d1116cdcc57e58287d3f55285a1084b 

Trả lời

14
#!/usr/bin/perl 

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

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

Cảm ơn này hoạt động tuyệt vời và tôi có thể gọi kịch bản này trong vòng kịch bản phân tích cú pháp của tôi trước khi chạy các mã phân tích cú pháp để nó chạy trên tất cả các file tạm thời . –

+0

Bất kỳ đề xuất nào về cuốn sách nào tôi nên chọn để tìm hiểu về Perl. Tôi mới làm quen với UNIX và gần đây đã bắt đầu học bash, sed và awk. –

+3

Có lẽ * [Học Perl] (http://www.amazon.com/dp/1449303587) *. –

-1

Nó phụ thuộc nếu đó là một dòng duy nhất trong temp tập tin của bạn hay không. Nhưng giả sử nếu đó là một dòng duy nhất, bạn có thể đi với:

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

Các sed chèn đầu tiên một # như một tách lĩnh vực/hồ sơ, sau đó awk chia rẽ trên # và in tất cả các "trường" để tập tin riêng của mình.

Nếu tập tin đầu vào đã được chia trên 3d3d sau đó bạn có thể đi với:

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

HTH

5

này có thể làm việc:

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

Nếu có là các dòng mới trong tệp nguồn, bạn có thể xóa chúng trước bằng cách sử dụng tr -d '\n' <temp và sau đó đường ống đầu ra thông qua lệnh trên sed. Tuy nhiên, nếu bạn muốn bảo vệ họ thì:

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

Nên làm các trick

16

Các RS biến trong awk là tốt đẹp cho điều này, cho phép bạn xác định các dấu phân cách kỷ lục. Vì vậy, bạn chỉ cần nắm bắt từng bản ghi trong tệp tạm thời của chính nó. Phiên bản đơn giản nhất là:

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

Văn bản mẫu bắt đầu bằng công cụ bắt mắt 3d3d, vì vậy temp1 sẽ là một tệp trống. Hơn nữa, bản thân trình thu hút sẽ không ở đầu các tệp tạm thời, như được hiển thị cho các tệp tạm thời trong câu hỏi. Cuối cùng, nếu có nhiều bản ghi, bạn có thể chạy vào giới hạn hệ thống đối với các tệp đang mở. Một số biến chứng nhẹ sẽ mang lại cho nó gần gũi hơn với những gì bạn muốn và làm cho nó an toàn hơn:

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

Khm, bạn don không cần 'mèo' vì điều đó. Và nếu đó là đầu vào một dòng, bạn sẽ chỉ nhận được bản ghi đầu tiên. Và đầu ra sẽ bỏ lỡ bản gốc 'RS'. 'echo '3d3dsomething3d3danything' | awk 'BEGIN {RS = "3d3d"} {print}' 'sẽ chỉ xuất ra' cái gì đó'. –

+1

Hoặc tôi đã sai. Vấn đề duy nhất với giải pháp của bạn là thiếu 'RS' trong đầu ra. (Và việc sử dụng vô ích của 'cat'.) –

+2

@ZsoltBotykai RS nằm ở đầu ra, như đã thảo luận. Và mèo không phải là vô ích: nó cung cấp sự tách biệt hợp lý giữa việc tạo ra dữ liệu và xử lý. Vì vậy, 'cat temp' là viết tắt của bất kỳ biến đổi nào diễn ra trước giai đoạn lúng túng, trong khi tránh thêm nhiều hơn nữa vào dòng đã dài với awk. –

Các vấn đề liên quan