バイナリテキストファイルからJPEG画像を抽出しようとしています。 0xFF 0xD8(画像の開始)と0xFF 0xD9(画像の終わり)の間のすべてのデータを抽出したいと思います。以前は、received.txtという単一の段落ファイルから目的のimage.jpgを取得するために、次のコマンドを正常に実行しました。
sed 's/.*\xFF\xD8/\xFF\xD8/; s/\xFF\xD9.*/\xFF\xD9/' received.txt > image.jpg
ただし、他のファイルに対して同じタスクを実行しようとすると機能しません。私も試しました。
sed -n '/\xFF\xD8/,/\xFF\xD9/p' received.txt > temp.txt
sed 's/.*\xFF\xD8/\xFF\xD8/; s/\xFF\xD9.*/\xFF\xD9/' temp.txt > image.jpg
成功せずに一致する行の前後の行を削除します。
ファイルが大きすぎますが、下に関連部分の16進ダンプを貼り付けました。
0a 55 57 5d 50 cf ff d8 ff fe ff ff ff d9 df 47 fe e7 c9 3b e9 9b 6b 55 c4 57 9b 98 73 fd 15 f7 77 7e f7 95 dd 55 f7 55 05 cc 55 97 55 dd 62 d1 1f 51 ef f1 ef fb e9 bf ed 5f bf f2 9d 75 af fe 6b fb bf 8f f7 f7 7e ff d3 bf 8e d5 5f df 57 75 fe 77 7b bf d7 af df 5d fb 0a 47 de d5 ff c1 23 9b 20 08 20 65 3c 06 83 11 05 30 50 a0 20 55 20 84 41 04 c2 59 50 89 64 44 44 10 05 20 87 28 1d a9
この場合、目的の出力の16進ダンプは次のようになります。
ff d8 ff fe ff ff ff d9
修正する
問題を解決しようとしたときに、sedコマンドは一致するパターンの前後のすべての文字を非ASCII文字(0x80 - 0xFF)まで削除しますが、それ以上は削除しないことがわかりました。たとえば、次のようにしましょう。
echo 55 57 5d 50 cf 50 65 7f ff d8 ff fe ff ff ff d9 | xxd -r -p | sed 's/.*\xFF\xD8/\xFF\xD8/' > output
出力16進ダンプは次のように表示できます。
xxd output
これは:
55 57 5d 50 cf ff d8 ff fe ff ff ff d9
ご覧のとおり、非ASCII文字と一致するパターン間の文字は削除されますが、非ASCII文字の前の文字は削除されません。
代替ソリューション(完璧ではない)
次のコマンドを使用して問題をある程度解決しました。
sed 's/\xFF\xD8/\x0A\xFF\xD8/; s/\xFF\xD9/\xFF\xD9\x0A/' received.txt > temp.txt
次に、次のコマンドを実行します(0xFF 0xD8と0xFF 0xD9の間に改行文字(0x0A)がない場合、このコマンドは機能します)。
sed -n '/\xFF\xD8/{/\xFF\xD9/p}' temp.txt > image.jpg
ただし、image.jpgファイルが空の場合(上記のコマンドを実行した後)、次のコマンドを実行してください。
sed -n '/\xFF\xD8/,/\xFF\xD9/p' temp.txt > image.jpg
このコマンドは、image.jpgファイルの終わり(つまり0xFF 0xD9の後ろ)に0x0Aを置くことを除いて必要な操作を実行します。私の場合、JPEGファイルは0xFF 0xD9マーク以降のデータを自動的に削除するため、問題は発生しませんでした。
@chaosが完璧なソリューションを提示している間、「画像ファイルが空の場合」の条件実装に閉じ込められていました。だから私は今彼の解決策に従います。 @chaos 本当にありがとう!
メモ:
sedコマンドでパイプできる16進ダンプから実際のデータを取得する方法は次のとおりです。
echo 0a 55 57 5d 50 cf ff d8 ff fe ff ff ff d9 df 47 fe e7 c9 3b e9 9b 6b 55 c4 57 9b 98 73 fd 15 f7 77 7e f7 95 dd 55 f7 55 05 cc 55 97 55 dd 62 d1 1f 51 ef f1 ef fb e9 bf ed 5f bf f2 9d 75 af fe 6b fb bf 8f f7 f7 7e ff d3 bf 8e d5 5f df 57 75 fe 77 7b bf d7 af df 5d fb 0a 47 de d5 ff c1 23 9b 20 08 20 65 3c 06 83 11 05 30 50 a0 20 55 20 84 41 04 c2 59 50 89 64 44 44 10 05 20 87 28 1d a9 | xxd -r -p
次のようにして、ファイルの16進ダンプを表示できます。
xxd file.txt
答え1
サンプルデータの使用とgrep
PCRE(Perl正規表現)の有効化(-P
):
grep -oP '\xFF\xD8.*\xFF\xD9' input >image.jpeg
この-o
フラグは、grep
一致する部分だけを印刷することを意味します。その後のテストでは有望に見えました。
$ file image.jpeg
image.jpeg: JPEG image data
編集する:上記の方法が機能せず、必ず機能する必要がある場合は、sed
データをテキストに変換する必要があります。
hexdump -ve '1/1 "%.2X"' input | sed 's/.*\(FFD8.*FFD9\).*/\1/' | xxd -r -p >image.jpeg
- ファイルはあなたの質問に似たシーケンスに変換されます
hexdump
。input
-e
書式設定1/1
1 回の形式 (反復回数) を適用した後、各反復に対して解釈するバイト数 (バイト数) を1
指定することを示します。/
%.2X
形式は2桁の16進値です。
- その後、ダンプ
sed
の前後のすべての内容を削除してくださいFFD8
。FFD9
- 角かっこは、
\(...\)
後で使用するために保存するサブパターンを指定します。 \1
すべてを上記のサブパターンの内容であると置き換えます。
- 角かっこは、
- 少なくとも
xxd
16進ダンプをバイナリ形式に戻してください。
質問の例を使用するとテストが成功します。
$ echo 0a 55 57 5d 50 cf ff d8 ff fe ff ff ff d9 df 47 fe e7 c9 3b e9 9b 6b 55 c4 57 9b 98 73 fd 15 f7 77 7e f7 95 dd 55 f7 55 05 cc 55 97 55 dd 62 d1 1f 51 ef f1 ef fb e9 bf ed 5f bf f2 9d 75 af fe 6b fb bf 8f f7 f7 7e ff d3 bf 8e d5 5f df 57 75 fe 77 7b bf d7 af df 5d fb 0a 47 de d5 ff c1 23 9b 20 08 20 65 3c 06 83 11 05 30 50 a0 20 55 20 84 41 04 c2 59 50 89 64 44 44 10 05 20 87 28 1d a9 | \
xxd -r -p | \
hexdump -ve '1/1 "%.2X"' | \
sed 's/.*\(FFD8.*FFD9\).*/\1/' | \
xxd -r -p >image.jpeg
$
$ file image.jpeg
image.jpeg: JPEG image data
$ xxd image.jpeg
0000000: ffd8 fffe ffff ffd9 ........
答え2
@chaosソリューションにもっと追加したいと思いました。
hexdump -ve '1/1 "%.2X "' input | sed 's/.*\(FF D8.*FF D9\).*/\1/' | xxd -r -p > image.jpeg
私と後ろ%.2X
との間にFFD8
スペースを追加しましたFFD9
。これは、次の移動パターンの一致を防ぐためです。
0f fd 80 ... 0f fd 90