it-swarm-vi.com

Cách tốt nhất để loại bỏ byte từ đầu tập tin?

Hôm nay tôi đã phải loại bỏ 1131 byte đầu tiên khỏi tệp nhị phân/văn bản hỗn hợp 800 MB, một bãi chứa Subversion được lọc mà tôi đang hack cho một kho lưu trữ mới. Cách tốt nhất để làm điều này là gì?

Để bắt đầu với tôi đã cố gắng

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

nhưng sau khi bỏ qua việc này sẽ sao chép phần còn lại của tệp một byte tại một thời điểm, tức là rất chậm. Cuối cùng, tôi đã cần tới 405 byte để làm tròn số này lên đến ba khối 512 mà tôi có thể bỏ qua

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

hoàn thành khá nhanh nhưng phải có cách đơn giản/tốt hơn? Có công cụ nào khác mà tôi đã quên không? Cảm ơn!

64
Rup

Bạn có thể chuyển đổi bs và bỏ qua các tùy chọn:

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

Bằng cách này, hoạt động có thể được hưởng lợi từ một khối lớn hơn.

Mặt khác, bạn có thể thử với đuôi (mặc dù không an toàn khi sử dụng tệp nhị phân):

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

Cuối cùng, bạn có thể sử dụng 3 trường hợp dd để viết một cái gì đó như thế này:

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

trong đó dd đầu tiên in đầu ra tiêu chuẩn của nó được lọc.dump; cái thứ hai chỉ đọc 1131 byte và ném chúng đi; sau đó, cái cuối cùng đọc từ đầu vào tiêu chuẩn của nó các byte còn lại của filtered.dump và ghi chúng vào trimmed.dump.

67
marco

Không chắc chắn khi skip_bytes đã được thêm, nhưng để bỏ qua 11 byte đầu tiên bạn có:

# 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

Ở đâu iflag=skip_bytes yêu cầu dd diễn giải giá trị cho tùy chọn skip dưới dạng byte thay vì khối, làm cho nó đơn giản.

Bạn có thể sử dụng một Shell con và hai cuộc gọi dd như thế này:

$ ( 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

Nếu hệ thống tập tin và nhân Linux hỗ trợ thì bạn có thể thử fallocate nếu bạn muốn thực hiện các thay đổi tại chỗ: trong trường hợp tốt nhất không có dữ liệu IO cả:

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

ở đâu <magic> phụ thuộc vào hệ thống tệp, phiên bản Linux và loại tệp ( FALLOC_FL_COLLAPSE_RANGE hoặc là FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE có thể được sử dụng nội bộ ).

7
jfs

Bạn nên sử dụng count=0 - đó là một lseek() đơn giản bất cứ khi nào có thể.

Như thế này:

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

dd will lseek() bộ mô tả tệp đầu vào thành phần bù 1131 byte, và sau đó cat sẽ chỉ sao chép bất cứ thứ gì còn lại vào đầu ra.

3
mikeserv

Tuy nhiên, một cách khác để loại bỏ các byte hàng đầu khỏi một tệp (hoàn toàn không sử dụng dd) là sử dụng xxdsed hoặc 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 yêu cầu một lớp lót trực tuyến. Đây là một trong Perl. Phải mất 2 đối số: Từ byte và chiều dài. Tệp đầu vào phải được cung cấp bởi '<' và đầu ra sẽ ở trên thiết bị xuất chuẩn:

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

Nếu độ dài lớn hơn tệp, phần còn lại của tệp sẽ được sao chép.

Trên hệ thống của tôi, điều này cung cấp 3,5 GB/s.

2
Ole Tange