私は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バイトのデータブロックのため、ループはfor
12回実行されませんが、代わりにより多くのデータが配列を満たすまで待ちます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バイトを格納できません(zsh
NULバイトのみを保存できますが、ksh93
'sも参照printf %B
してtypeset -b
base64エンコーディングを使用してください)。組み込み関数は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
)。