ローカルまたはネットワークの場所からパイプを介して圧縮ファイルを送信しています。受信側では圧縮タイプを検出し、適切な解凍ユーティリティ(gzip、bzip2、xzなど)を使用して解凍したいと思います。コマンドは次のとおりです。
ローカル:
cat misteryCompressedFile | [compressionUtility] -d -fc > /opt/files/uncompressedfile
インターネット経由:
ssh user@ipaddr "cat misteryCompressedFile" | [compressionUtility] -d -fc > /opt/files/uncompressedfile
拡張子が指定されていなくても(.gzや.bz2など)、ファイルの最初の16進数の値を見ると、使用されている圧縮の種類がわかります。たとえば、xxd
2 つの圧縮ファイルの最初の 16 進値を調べるには、1f8b 0808
gzip と425a 6836
bzip2 を見てみましょう。
しかし、パイプを引き続き使用するには、最初のファイルの正しい解凍ユーティリティを選択するために最初の受信バイトを確認する必要がありますか?
したがって、不明な圧縮ファイルがgzipタイプの場合、コマンドは次のようになります。
cat misteryCompressedFile | gzip -d -fc > /opt/files/uncompressedfile
不明な圧縮ファイルがbzip2タイプの場合、コマンドは次のようになります。
cat misteryCompressedFile | bzip2 -d -fc > /opt/files/uncompressedfile
ファイル全体をダウンロードしてから、解凍に何を使用するかを決定することなく、パイプラインを介して動的にそのような決定を下すことはできますか?
ベストアンサー1
はい、ファイル全体を読み取ることなくパイプでこれを行うことができます。
最初のスクリプトスニペットは、ヘッダーを傍受し、チェックして渡すメカニズムを示しています。ヘッダーはstderr(>&2)として印刷されますが、出力にはまだ表示されます。
$ echo 0123456789ABCDEF |
(
HEADER=$(dd bs=1 count=4);
printf 'HEADER:%s\n' "$HEADER" >&2;
printf '%s\n' "$HEADER";
cat
)
4+0 records in
4+0 records out
4 bytes (4 B) copied, 8.4293e-05 s, 47.5 kB/s
HEADER:0123
0123456789ABCDEF
$
重要なのは、dd
小さなブロックサイズのファイル変換ユーティリティを使用することですbs=1
。
拡張すると、これが可能な解決策です。バイナリヘッダーを保存するために一時ファイルを使用します。 2つの4バイトヘッダーのいずれかが表示されない場合、何もしません。
#!/bin/sh
trap "rm -f /tmp/$$; exit 1" 1 2 3 15
# grab the 1st 4 bytes off the input stream,
# store them in a file, convert to ascii,
# and store in variable:
HEADER=$(
dd bs=1 count=4 2>/dev/null |
tee /tmp/$$ |
od -t x1 |
sed '
s/^00* //
s/ //g
q
'
)
case "$HEADER" in
1f8b0800)
UNCOMPRESS='gzip -d -fc'
;;
425a6839)
UNCOMPRESS='bzip2 -d -fc'
;;
*)
echo >&2 "$0: unknown stream type for header '$HEADER'"
exit 2
;;
esac
echo >&2 "$0: File header is '$HEADER' using '$UNCOMPRESS' on stream."
cat /tmp/$$ - | $UNCOMPRESS
rm /tmp/$$