如何在Bash中编写二进制数据

9

假设在Bash脚本中有一个取值为“001”的变量,如何将这个二进制数据以01位的形式写入文件(如“001”而不是“1”)?

echo会将其作为字符串输出,但我想以比特位的形式输出。


1
你不能将单个位写入文件。你可以写入的最小量是8位,即一个字节。 - that other guy
2
如何将8位字符串变量(例如“00000011”)写入文件? - Jeevansai Jinne
1
将字符 $'\x03' 以 printf 的方式输出到文件中。 - 123
2
@123 这个代码可以运行,但只有在值不是\x00的情况下才有效,因为这个值不能作为参数表示。 printf '\x00' 可以工作,因为它避免了直接传递二进制数据。 - that other guy
6个回答

18

你可以使用以下方式以十六进制或八进制编写任意字节:

printf '\x03' > file   # Hex
printf '\003' > file   # Octal

如果你有二进制,那就比较棘手,但是你可以使用以下方法将其转换为八进制:

    $ echo 'obase=8; ibase=2; 101010' | bc
    52

printf '%o\n' "$((2#00000011))"

当然,上面的内容可以嵌套使用:

binary=00000011
printf "\\$(printf '%o' "$((2#$binary))")" > file

请注意,这仅适用于最多8位。如果您想写更长的值,则必须将其分成8组。


写十进制和八进制有什么区别,两者都用于写入字节。 - Jeevansai Jinne
2
结果是相同的,不同之处仅在于您指定要写入的字节的方式。如果您想要写入全部为1的字节,则为\xFF\377。您可以使用任何一个您喜欢的来工作。 - that other guy

4

只需在 printf 中使用 %b

printf "%b" "\012"
printf "%b" "\x0a"

%b – 在解释反斜杠转义字符的同时打印关联参数

因此,上面两个语句都打印了十进制数值10的二进制值。

printf "%b" "\x0a" | od -bc

输出

0000000   012                                                            
          \n      

你甚至可以混合使用

printf "%b" "\12\xa\n" | od -bc

0000000   012 012 012                                                    
          \n  \n  \n            

2

以下是用于将整数输出到文件的一些更通用的函数:

Original Answer翻译成"最初的回答"

le16 () { # little endian 16 bit;  1st param: integer to 2nd param: file 
  v=`awk -v n=$1 'BEGIN{printf "%04X", n;}'`
  echo -n -e "\\x${v:2:2}\\x${v:0:2}" >> $2
}

le32 () { # 32 bit version
  v=`awk -v n=$1 'BEGIN{printf "%08X", n;}'`
  echo -n -e "\\x${v:6:2}\\x${v:4:2}\\x${v:2:2}\\x${v:0:2}" >> $2
}

awk在这里真的有帮助吗? 对我来说,使用普通的printf更加简洁:v=$(printf "%04X" "$1") - S-trace
awk在这里真的有帮助吗? 对我来说,使用简单的printf更加清晰:v=$(printf "%04X" "$1") - undefined

1

使用bc(在CentOS 7.4中):

VALUE="3F"
INPUT_BASE=16
OUTPUT_BASE=2
printf "%b\n" $(bc <<< "ibase=$INPUT_BASE; obase=$OUTPUT_BASE; $VALUE")

结果: 111111

如果需要前导零,则:

VALUE="3F"
INPUT_BASE=16
OUTPUT_BASE=2
printf "%16b\n" $(bc <<< "ibase=$INPUT_BASE; obase=$OUTPUT_BASE; $VALUE") | sed 's^ ^0^g'

结果: 0000000000111111

请注意在printf格式中使用的16;更改该值以限制前导零的数量


1

通常情况下,您需要编写一个模式(例如32位模式)。

# Write 32 bits 5 times to a file 
for i in {1..5}
do
   printf '\x12\x34\xAC\xCD' >> binaryfile.bin
done

另一个例子:

for i in {1..255}
do
    hx=$( printf "%x" $i )
    output="\x$hx\x00\x00\x00"
    printf "%b" $output >> binaryfile.bin 
done

1

最近我需要这个,希望有人会发现它很有用:

#!/bin/bash

# generate bitmasks for a C array

# loop counter
NUMBER=0
MAX_BITMASK_LENGTH=8
# max loop value : 2^8 = 255
MAXVAL=$((2**MAX_BITMASK_LENGTH))
# line number
LINE=0

# echo start of C array
echo "    const long int bitmasks[${MAX_BITMASK_LENGTH}] = {"

# loop over range of values
while [ ${NUMBER} -le ${MAXVAL} ] ; do

    # use bc to convert to binary
    BINARY=`echo -e "obase=2\n${NUMBER}"| bc`

    # print current number, linenumber, binary
    printf "%12s, /* (%i) %8s */\n" ${NUMBER} ${LINE} ${BINARY}

    # increase loop value to next value
    NUMBER=$(((NUMBER*2)+1))

    # increment line number
    LINE=$((LINE+1))
done

# echo end of C array
echo "        };"

这将输出:

$ ./generate_bitmasks.sh
    const long int bitmasks[8] = {
           0, /* (0)        0 */
           1, /* (1)        1 */
           3, /* (2)       11 */
           7, /* (3)      111 */
          15, /* (4)     1111 */
          31, /* (5)    11111 */
          63, /* (6)   111111 */
         127, /* (7)  1111111 */
         255, /* (8) 11111111 */
        };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接