今日、800 MBの混合テキスト/バイナリファイルから、最初の1131バイトを削除する必要がありました。これは、新しいリポジトリ用にハッキングしている、フィルタリングされたSubversionダンプです。これを行う最良の方法は何ですか?
最初に私が試した
dd bs=1 skip=1131 if=filtered.dump of=trimmed.dump
しかし、スキップ後、これはファイルの残りを一度に1バイトずつ、つまり非常にゆっくりとコピーします。最後に私は解決しました、これを512の3ブロックに丸めるために405バイトが必要でしたが、スキップすることができました
dd if=/dev/zero of=405zeros bs=1 count=405
cat 405zeros filtered.dump | dd bs=512 skip=3 of=trimmed.dump
どれがかなり早く完了しましたが、もっと簡単で良い方法があったに違いありませんか?忘れていた別のツールはありますか?ありがとう!
あなたはbsを切り替えてオプションをスキップすることができます:
dd bs=1131 skip=1 if=filtered.dump of=trimmed.dump
このようにして、操作はより大きなブロックから利益を得ることができます。
そうでない場合は、tailで試すことができます(ただし、バイナリファイルで使用するのは安全ではありません)。
tail -c +1132 filtered.dump >trimmed.dump
最後に、3つのddインスタンスを使用して次のようなものを書くことができます:
dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }
ここで、最初のddはその標準出力であるfiltered.dumpを出力します。 2つ目は1131バイトを読み取り、それらを破棄します。次に、最後のものはその標準入力からfiltered.dumpの残りのバイトを読み取り、それらをtrimmed.dumpに書き込みます。
skip_bytes
が追加されましたが、最初の11バイトをスキップするには、次のようにします。
# 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
どこ iflag=skip_bytes
は、skip
オプションの値をブロックではなくバイトとして解釈するようにddに指示し、それを簡単にします。
次のように、サブシェルと2つのdd
呼び出しを使用できます。
$ ( 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
ファイルシステムとLinuxカーネルがそれをサポートしている場合、変更を適用したい場合は fallocate
を試すことができます。最良の場合、データはありませんIOまったく:
$ fallocate <magic> -o 0 -l 1131 inplace.dump
どこ <magic>
は、ファイルシステム、Linuxバージョン、およびファイルタイプ( FALLOC_FL_COLLAPSE_RANGE
またはFALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE
は内部で使用できます )。
_count=0
_を使用する必要があります。これは、可能な限り単純なlseek()
です。
このような:
_{ dd bs=1131 skip=1 count=0; cat; } <filtered.dump >trimmed.dump
_
dd
は、入力ファイル記述子を1131バイトのオフセットにlseek()
し、cat
は、残っているものを出力にコピーするだけです。
(dd
をまったく使用せずに)ファイルから先頭バイトを削除するさらに別の方法は、それぞれxxd
およびsed
または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
@maxschlepzigはオンラインライナーを要求します。これはPerlの1つです。 2つの引数を取ります:バイトと長さから。入力ファイルは「<」で指定する必要があり、出力は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
長さがファイルより大きい場合、ファイルの残りの部分がコピーされます。
私のシステムでは、これは3.5 GB /秒を提供します。