
文字を読んだ後、固定長文字列(ファイル内でnullで終わらずに前の文字で長さが指定されています)を読みたいと思います。
Bashスクリプトでこれをどのように実行できますか?後処理を実行できるように文字列変数をどのように定義しますか?
答え1
シェルユーティリティを引き続き使用するには、head
複数のバイトを抽出し、od
バイトを数値に変換するために使用できます。
export LC_ALL=C # make sure we aren't in a multibyte locale
n=$(head -c 1 | od -An -t u1)
string=$(head -c $n)
しかし、動作しませんバイナリデータの場合。 2つの質問があります。
コマンド置換
$(…)
バー最後の改行文字コマンド出力から。非常に簡単な解決策があります。出力が改行以外の文字で終わっていることを確認し、その文字を削除します。string=$(head -c $n; echo .); string=${string%.}
ほとんどのシェルと同様に、Bashは処理にうまくいきません。ヌルバイト。 Bash 4.1以降、コマンド置換の結果からヌルバイトが単純に削除されます。 Dash 0.5.5 と pdksh 5.2 は同じ動作を持ち、ATT ksh は最初の null バイトで読み出しを停止します。通常、シェルとそのユーティリティはバイナリファイルの処理には適していません。 (ヌルバイトをサポートするように設計されたZshは例外です。)
バイナリデータがある場合は、PerlやPythonなどの言語に切り替える必要があります。
<input_file perl -e '
read STDIN, $c, 1 or die $!; # read length byte
$n = read STDIN, $s, ord($c); # read data
die $! if !defined $n;
die "Input file too short" if ($n != ord($c));
# Process $s here
'
<input_file python -c '
import sys
n = ord(sys.stdin.read(1)) # read length byte
s = sys.stdin.read(n) # read data
if len(s) < n: raise ValueError("input file too short")
# Process s here
'
答え2
シェルでバイナリを処理したい場合は、最良のオプションは(唯一の?)以下を使用することです。16進ダンプツール。
hexdump -v -e '/1 "%u\n"' binary.file | while read c; do
echo $c
done
Xバイトのみを読む:
head -cX binary.file | hexdump -v -e '/1 "%u\n"' | while read c; do
echo $c
done
長さを読み取り(長さ0を使用)、バイトの10進値で「文字列」を読み込みます。
len=$(head -c1 binary.file | hexdump -v -e '/1 "%u\n"')
if [ $len -gt 0 ]; then
tail -c+2 binary.file | head -c$len | hexdump -v -e '/1 "%u\n"' | while read c; do
echo $c
done
fi
答え3
exec 3<binary.file # open the file for reading on file descriptor 3
IFS= #
read -N1 -u3 char # read 1 character into variable "char"
# to obtain the ordinal value of the char "char"
num=$(printf %s "$char" | od -An -vtu1 | sed 's/^[[:space:]]*//')
read -N$num -u3 str # read "num" chars
exec 3<&- # close fd 3
答え4
これはバイナリファイルをコピーします。
while read -n 1 byte ; do printf "%b" "$byte" ; done < "$input" > "$output"