我想读取一个字符,然后读取固定长度的字符串(该字符串在文件中不是以空结尾,其长度由前面的字符给出)。
我怎样才能在 bash 脚本中做到这一点?如何定义字符串变量以便我可以对其进行一些后处理?
答案1
如果您想坚持使用 shell 实用程序,您可以使用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)
然而,这不起作用对于二进制数据。有两个问题:
命令替换
$(…)
条最后的换行符在命令输出中。有一种相当简单的解决方法:确保输出以换行符以外的字符结尾,然后删除该字符。string=$(head -c $n; echo .); string=${string%.}
Bash 与大多数 shell 一样,不擅长处理空字节。从 bash 4.1 开始,空字节被简单地从命令替换的结果中删除。 Dash 0.5.5 和 pdksh 5.2 具有相同的行为,并且 ATT ksh 在第一个空字节处停止读取。一般来说,shell 及其实用程序不适合处理二进制文件。 (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
如果您希望能够在 shell 中处理二进制文件,最好的选择(唯一?)是使用十六进制转储工具。
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 作为长度),然后将“string”作为字节十进制值:
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"