【问题标题】:How to write a binary file using Bash?如何使用 Bash 编写二进制文件?
【发布时间】:2011-07-31 18:22:56
【问题描述】:

我的问题是我需要用这个确切的字节创建一个文件:48, 00, 49, 00

我不能使用 C、perl、其他脚本语言(目标是嵌入式设备)。我用 awk 试过了,在桌面上它确实有效:

# awk  'BEGIN{ printf "%c%c%c%c", 48, 00, 49, 00 }' | hexdump
0000000 0030 0031                              
0000004

但是目标平台正在运行busybox v1.13.2,并且此代码在那里不起作用。那里的awk版本不输出ascii“0”(其他值都ok)。

你有什么建议?

【问题讨论】:

    标签: bash awk busybox


    【解决方案1】:

    您可以使用以下命令:

    echo -n -e \\x48\\x00\\x49\\x00 > myfile
    

    【讨论】:

    • 谢谢。发生了同样的问题,只有在路由器内部可以访问 bash。 Perl 和 C 是一个梦想。我使用该设备与其他从设备进行 rs485 通信,并且交换效果很好!
    • 谢谢。美好的事物,是永远的快乐
    【解决方案2】:

    你可以试试 echo,它也允许任意 ascii 字符(这些数字是八进制数)。

    echo -n -e \\0060\\0000\\0061\\0000  | hexdump
    

    【讨论】:

    • ...和十六进制..?这可能吗?
    • 不,echo 只接受八进制数。但是您要求特定的给定十六进制序列(我什至为您将它们翻译成八进制)。如果您不确定如何转换,请在 ascii 的手册页中查找不同的十六进制序列。它会给你一个十进制、十六进制和八进制数字的表格;-)。
    • 仅供将来参考,它确实接受十六进制。只需使用 \\xNN ,其中 N 是十六进制数字。
    【解决方案3】:

    POSIX AWK 标准规定,将 0 传递给 AWK 的 printf 以 %c 格式可能会导致未指定的行为。然而...... POSIX echo 也非常有限,虽然八进制和十六进制说明符(和 -n)将适用于 GNU echo 和 BASH 内置......它们可能无法在任何地方使用。为了最大限度地提高您在所有 POSIX 系统上获得一致行为的机会,最好使用 shell 命令行的 printf,而不是其中任何一个。

    $ printf '\060\000\061\000' | od -An -tx1
     30 00 31 00
    

    这对我来说看起来很奇怪......您可能想要输出 0x48、0x00、0x49、0x00 ——这看起来像是一个漂亮的八进制试点数字:

    $ printf '\110\000\111\000' | od -An -tx1
     48 00 49 00
    

    【讨论】:

      【解决方案4】:

      我需要在旧的 Android shell 中使用 busybox 从十六进制写入二进制文件。这个带有重定向的printf 在我的用例中有效。

      用十六进制写入二进制数据:

      # busybox printf '\x74\x65\x73\x74' > /sdcard/test.txt
      

      以十六进制显示结果:

      # busybox hexdump -C /sdcard/test.txt
      00000000  74 65 73 74                                       |test|
      00000004
      

      以 ascii 显示结果:

      # cat /sdcard/test.txt
      test
      

      【讨论】:

      • 为什么要使用dd?为什么busybox printf '\x74\x65\x73\x74' > /sdcard/test.txt 不起作用?
      • 哇,你说得对!我确信我试过了。我确实尝试了所有这些答案以及其他十几个都失败的答案。就是这么简单。混合中一定还有其他变量。我会修改我的答案。谢谢!
      【解决方案5】:

      几个更通用的函数来输出整数:

      le16 () { # little endian 16 bit binary output 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
      }
      

      用于为 iio 数据流制作音频 WAV 文件头:

      channels=2
      bits_per_sample=16
      let "block_align = channels * bits_per_sample / 8"    
      
      wave_header () { # pass file name and data size as parameters; rest are constants set elsewhere
        data_size=$2
        let "RIFFsize = data_size + 44 - 8"
        let "bytes_per_sec = sampleHz * block_align"
      
        echo -e -n "RIFF" > $1
          le32 $RIFFsize $1
        echo -e -n "WAVEfmt " >> $1
          le32 16 $1  # format size
          le16 1 $1   #format tag: 1 = PCM
          le16 $channels $1
          le32 $sampleHz $1
          le32 $bytes_per_sec $1
          le16 $block_align $1
          le16 $bits_per_sample $1   # bits per sample
        echo -e -n "data" >> $1
          le32 $data_size $1
      }
      

      Linux iio ADC 数据采集到 WAV 文件:

      sampleHz=8000
      milliseconds=15  # capture length 
      
      cd /sys/bus/iio/devices/iio:device0
      
      cat /sys/bus/iio/devices/trigger0/name > trigger/current_trigger
      
      echo 0 > buffer/enable
      
      echo 0 > scan_elements/in_voltage0_en  #
      echo 1 > scan_elements/in_voltage1_en  #  
      echo 1 > scan_elements/in_voltage2_en  # 
      echo 0 > scan_elements/in_voltage3_en  #
      
      echo $sampleHz > sampling_frequency
      sampleHz=`cat sampling_frequency`  # read back actual sample rate
      
      let "buffer_length = block_align * sampleHz * milliseconds / 1000"
      echo $buffer_length > buffer/length
      
      cd $HOME
      
      echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
      wave_header data.wav $buffer_length
      head -c $buffer_length /dev/iio:device0 >> data.wav  # LE16 data
      echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
      

      【讨论】:

        【解决方案6】:

        我不知道busybox中有什么,但这可能会起作用,因为printf小于awk。

        $ printf "%c%c%c%c" 48 0 49 0 | hexdump
        

        这是输出:

        $ printf "%c" 1 | hexdump
        0000000 0031                    
        

        【讨论】:

        • 我用我所看到的编辑了你的答案,这不是我问的。这将打印 0x31,这是字符“1”的 ASCII 值。
        • 因此,如果您将 1 替换为 H 和 I,您将获得所需的值 0x48、0x49 - 而不是十进制的 48/49(使用 0 和 1)。有问题的部分是获得零字节以不终止输出。然后将上面的内容转换为printf "%c%c%c%c" 72 0 73 0 | hexdump 输出 0x48 0x00 0x49 0x00。
        猜你喜欢
        • 1970-01-01
        • 2012-02-12
        • 2010-12-02
        • 1970-01-01
        • 1970-01-01
        • 2011-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多