BASH組み込み読み取りを使用して0バイトを含むバイナリデータを読み取るには?

BASH組み込み読み取りを使用して0バイトを含むバイナリデータを読み取るには?

私はread buildinコマンドを使用して読み取ると、bashが入力時にバイナリ0を無視することがわかりました。この問題を解決する方法はありますか?

タスクは、一度に12バイトのバイナリブロック、つまり16ビット整数2個と32ビット整数2個を転送するパイプからデータを読み取ることです。データレートは低く、パフォーマンスに問題はありません。 bash変数はCスタイルなので明らかにread -N 12 struct効果がなく、NUL以上のバイトにはアクセスできません。したがって、バイト単位でデータを読み取る必要があるようですread -N 1 byte。解決しやすい問題は、エスケープ(必須-r)とUTFマルチバイト文字エンコーディング(export LC_ALL=C)です。これまで解決できない問題は、ゼロバイトを処理することです。私はそれらが空の変数として現れると思いましたが、byte実際にread -r -N 1 byteはゼロではまったく返さず(0を無視して)、代わりにデータストリームから0以外の次のバイトを返します。

これが私がやろうとしていることで、ゼロが入力されていない限り完全に機能します。

export LC_ALL=C

while true;
  do
     for ((index = 0; index < 12; index++))
       do
          read -r -N 1 byte
          if [ -n "${byte}" ]; then
               struct[${index}]=$(echo -n "${byte}" | od -An -td1)
             else
               struct[${index}]=0
            fi
       done
... # some arithmetics reconstructing the four bitfields and processing them
  done < pipe

elseの分岐は決して使用されないことがわかりましたif。 0を含む12バイトのデータブロックのため、ループはfor12回実行されませんが、代わりにより多くのデータが配列を満たすまで待ち​​ますstruct。次のコマンドを使用して、パイプに12バイトを供給してこの動作を示します。

echo -en "ABCDE\tGH\0JKL" > pipe

自分をだましやすいのでゼロを送ることを確認しました。

~# mkfifo pipe
~# od -An -td1 <pipe &
[1] 25512
~# echo -en "ABCDE\tGH\0JKL" > pipe
~#    65   66   67   68   69    9   71   72    0   74   75   76

[1]+  Done                    od -An -td1 < /root/pipe

bashのこれらの動作を変更する方法はありますか?それとも、0バイトをどのように読み取ることができますか?

ベストアンサー1

bash変数はNULバイトを格納できません(zshNULバイトのみを保存できますが、ksh93'sも参照printf %Bしてtypeset -bbase64エンコーディングを使用してください)。組み込み関数はread入力からNULバイトもスキップします。

ただし、ここでは以下を使用できます。

LC_ALL=C IFS= read -rd '' -n1 c

つまり、NULで区切られたレコードから最大1バイトを読み取ります。したがって、空の場合は、EOF(ただし終了ステータスはゼロではない)またはNULバイトを読み取ったことを$c意味します。read

どちらの場合も、以下を使用してバイトの数値を取得できます。

LC_ALL=C printf -v value %d "'$c"

だから:

while
  IFS= LC_ALL=C read -rd '' -n1 c &&
    LC_ALL=C printf -v value %d "'$c"
do
  echo "Got byte with value $value"
done

EOFまで一度に1バイトずつ読み込み、NULバイトをサポートします。

またはこれを行うこともできます:

value=$(dd bs=1 count=1 2> /dev/null | od -An -vtu1)

またはいくつかのod実装を介して:

value=$(od -N1 -An -vtu1)

icanonこれは追加のプロセスを分岐し、外部実行可能ファイルを実行することを意味します(stdinがターミナルデバイスの場合はモードから外れませんread)。

おすすめ記事