Bashでバイナリファイルを使用して変換なしで文字通りバイトをコピーするにはどうすればよいですか?

Bashでバイナリファイルを使用して変換なしで文字通りバイトをコピーするにはどうすればよいですか?

私はいくつかの理由でC ++コードをbashに野心的に変換したいと思います。

コードは、完全にバイナリで書かれ、構成された私のサブフィールドに関連するファイル形式を読み取って動作します。私の最初のバイナリ関連の仕事は、ヘッダーの最初の988バイトをそのままコピーして、残りの情報を生成しながら書き込み可能な出力ファイルに入れることでした。

私は現在の解決策がうまくいかないと確信しており、実際にこれを決定する良い方法を見つけることができませんでした。したがって、実際に正しく書かれていても、それを確認するためにテストする方法を知る必要があります!

これが私が今やっていることです:

hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}
headInput=`head -c 988 ${inputTrack} | hexdump`
headOutput=`head -c 988 ${output_hdr} | hexdump`
if [ "${headInput}" != "${headOutput}" ]; then echo "output header was not written properly.  exiting.  please troubleshoot."; exit 1; fi

hexdump / xxdを使用してファイルのこの部分を調べると、内容を正確に読み取ることはできませんが、何かが間違っているようです。そして、比較のために私が書いたコードは、2つの文字列が同じかどうかを教えてくれます。

Bashでこれを行うより良い方法はありますか?デフォルトのバイナリのバイナリバイトをコピー/読み取りしてファイルにそのままコピーできますか? (好ましくは変数としても保存されます)。

ベストアンサー1

通常、シェルスクリプトで低レベルのバイナリデータを処理することはお勧めできません。

bash変数にバイト0を含めることはできません。zshこのバイトを変数に格納できる唯一のシェルです。

execveどの状況でも、コマンドパラメータと環境変数にこれらのバイトを含めることはできません。これは、システムコールに渡されるNULで区切られた文字列であるためです。

また注:

var=`cmd`

または現代的なモード:

var=$(cmd)

の出力からすべての末尾の改行を削除しますcmd。まあ、もしそうならバイナリ出力は0xaバイトで終わります$var

ここでは、例えばxxd -p

hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"

次のヘルパー関数を定義できます。

encode() {
  eval "$1"='$(
    shift
    "$@" | xxd -p  -c 0x7fffffff
    exit "${PIPESTATUS[0]}")'
}

decode() {
  printf %s "$1" | xxd -p -r
}

encode var cat /bin/ls &&
  decode "$var" | cmp - /bin/ls && echo OK

xxd -p出力は1バイトを2バイトにエンコードするため、スペース効率が悪くなりますが、作業(部分接続、抽出)を簡単に実行できます。base643バイトを4バイトにエンコードする方法ですが、使い方は簡単ではありません。

シェルには、対応するユーティリティおよび/ユーティリティで使用できる組み込みksh93エンコード形式(使用)があります。base64readprintfprint

typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output

シェル、環境変数、またはコマンドパラメータを介した転送がない場合は、使用するユーティリティがすべてのバイト値を処理できる場合は問題ありません。ただし、テキストユーティリティでは、GNU以外の実装のほとんどはNULバイトを処理できず、マルチバイト文字の問題を回避するにはロケールをCに変更する必要があります。改行以外の最後の文字は、非常に長い行だけでなく問題を引き起こす可能性があります(2つの0xaバイト間のバイトシーケンスがそれより長いですLINE_MAX)。

head -c利用可能な場合はバイトで作業し、データをテキストとして扱う理由がないので、ここでは問題ありません。だから

head -c 988 < input > output

大丈夫でしょう。実際、少なくともGNU、FreeBSD、およびksh93組み込みの実装はそうです。 POSIXはこの-cオプションを指定しませんが、headすべての長さの行をサポートする必要があることを示します(に限定されないLINE_MAX)。

そしてzsh

IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output

または:

var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output

NULバイトが含まれているzsh場合は、組み込み関数(上記のように)または関数に引数として渡すことができ$varますが、実行可能ファイルに渡された引数はNUL区切り文字ストリングなので、実行可能ファイルに渡すことはできません。カーネル制限であり、シェルとは何の関係もありません。zshprint

おすすめ記事