ファイルの先頭からバイトを削除する最良の方法は?


61

今日、私は800MBの混合テキスト/バイナリファイルから最初の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

どれがかなり早く完了しましたが、もっと簡単/より良い方法があったに違いありませんか?私が忘れていた別のツールはありますか?ありがとう!


dd仕事に最適なツールです-問題に対する優雅でエレガントな解決策を思いついたようです。
ジャスティンエティエ

回答:


62

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バイトを読み取り、それらを破棄します。次に、最後の1つは、filtered.dumpの残りのバイトを標準入力から読み取り、それらをtrimmed.dumpに書き込みます。


6
ありがとう!パイプ入力がそのような2番目のプロセスに引き継がれることを知りませんでした-それは非常にきれいです。考えもしなかったとは信じられないbs=1131 skip=1:-/
Rup

2
シェルユーティリティの最新の実装のほとんどは、バイナリファイルで正常に動作します(つまり、null文字で問題がなく、ファイルの末尾に余分な改行を挿入しません)。確かにGNUと* BSDの実装は安全です。
ジル 'SO-悪である停止

「バイナリファイルで使用するのは安全ではない」とはどういう意味ですか?
スコット

17

いつ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

where iflag=skip_bytesは、skipオプションの値をブロックではなくバイトとして解釈するようにddに指示します。


確かに、大きなファイルと少量のデータを削除する場合の速度の利点。
sstn

これは、すべてのブロックサイズで機能するため、ベストアンサーです。たとえば、iflag=skip_bytes skip=1234 bs=1M
phiresky

15

次のddようなサブシェルと2つの呼び出しを使用できます。

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

1
ありがとう-パイプ入力がそのような2番目のプロセスに続くことを知りませんでした、それはサブシェルだと思いますか?私は間違いなくそれを覚えています!彼が最初にここに来たので、マルコにダニを与えましたが、+ 1と答えに感謝します!
ラップ

1
@Rup、はい、括弧を介して作成されたサブシェルはstdinファイル記述子を提供し、両方のdd呼び出しはそこからの入力を連続して消費します。ええ-マルコは29秒で私を打ちました:)
maxschlepzig

6

ファイルシステムとLinuxカーネルがそれをサポートしているfallocate場合、変更をインプレースで行いたい場合に試すことができます:最良の場合、データIOはまったくありません:

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

where <magic>は、ファイルシステム、Linuxバージョン、およびファイルタイプによって異なります(FALLOC_FL_COLLAPSE_RANGEまたはFALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE内部で使用できます)。


1
これは私の好みの方法ですが、コンテナでこれを実行すると問題が発生します。 stackoverflow.com/questions/31155591/...
michaelcurry

3

あなたが使用する必要がありますcount=0-それはlseek()可能な限り簡単です。

このような:

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

ddlseek()1131バイトへの入力ファイル記述子はオフセットして、cat単純に出力に残っているものは何でもコピーします。


2

ddまったく使用せずに)ファイルから先頭のバイトを削除するさらに別の方法は、xxdand sedまたはor を使用すること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

それはきちんとしていますが、16進数への変換と16進数からの変換ではなく、バイナリでファイルを操作することを好みます。
ラップ

2

@maxschlepzigはオンラインライナーを要求します。perlに1つあります。2つの引数を取ります:バイトと長さから。入力ファイルは「<」で指定する必要があり、出力は標準出力になります。

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 /秒を提供します。


彼の1行の課題は、スクリプト言語ソリューションが1行のシェルソリューションよりも優れていることを証明してもらうことだったと思います。そして、私は彼のほうが好きです。あなたのパフォーマンスが優れているのは、彼よりも大きなブロックサイズを使用しているためです。
ラップ14

@Rup Alas、でもない。あなたはそれddが完全な読み取りを保証しないことを忘れているようです。試す:はい| dd bs = 1024k count = 10 | トイレunix.stackexchange.com/questions/17295/...
オーレ丹下

また、私のソリューションでは、必要のないバイト(数テラバイトの長さ)は読み取られません。
オレ丹下
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.