【问题标题】:Bash Script - Read Binary FileBash 脚本 - 读取二进制文件
【发布时间】:2010-12-30 15:25:40
【问题描述】:

我是脚本新手,但我有丰富的 C# 和 Java 等语言编程经验。

我有a file that contains binary data。我想编写一个 Bash 脚本来读取该文件中包含的年、月和日,以便我可以根据记录的日期将关联的 MOD 文件分类到文件夹中。我很难找到一种方法来读取二进制数据并在 bash 脚本中解析它。有没有办法做到这一点?

【问题讨论】:

  • 出于好奇,为什么是 bash 而不是 perl/python?
  • 真的没有理由。我已经写了一个 BASH 文件来重命名文件并移动它们。然后我认为最好按照文件的录制时间而不是我从相机中复制它们的时间对它们进行排序。

标签: bash scripting binaryfiles


【解决方案1】:

您可以为此使用 od(加上 head 和 awk 进行一些后期处理)。获取年份:

year=$(od -t x2 --skip-bytes=6 --read-bytes=2 file.moi | head -1 | awk '{print $2}')

当月:

month=$(od -t x1 --skip-bytes=8 --read-bytes=1 file.moi | head -1 | awk '{print $2}')

那天:

day=$(od -t x1 --skip-bytes=9 --read-bytes=1 file.moi | head -1 | awk '{print $2}')

【讨论】:

  • 效果很好。谢谢。实际上,我找到了一种从文件中获取日期的更好方法,而不是在阅读之前解析二进制数据。但是这段代码确实做了它应该做的事情。谢谢!
【解决方案2】:

我建议为此使用 python。

但是,如果您坚持使用 bash,我会尝试在二进制模式下使用 sed(从未尝试过)或使用 dd 提取特定字节然后转换它们。

【讨论】:

    【解决方案3】:

    如果这对你来说不是太难,我建议编译以下 C 语言程序:

    #include <stdio.h>
    #include <inttypes.h>
    
    typedef union {
      char array[sizeof(int32_t)];
      int32_t val;
    } int32_u;
    
    typedef union {
      char array[sizeof(uint32_t)];
      uint32_t val;
    } uint32_u;
    
    typedef union {
      char array[sizeof(uint64_t)];
      uint64_t val;
    } uint64_u;
    
    typedef union {
      char array[sizeof(int64_t)];
      int64_t val;
    } int64_u;
    
    int swap(char* mem, int size) {
      if (size & 1 != 0)
        return -1;
      int i;
      for (i = 0; i < size / 2; i++) {
        char tmp = mem[i];
        mem[i] = mem[size - i - 1];
        mem[size - i - 1] = tmp;
      }
      return 0;
    }
    
    int sys_big_endian() {
        int x = 1;
        return !(*(char*)&x);
    }
    
    int main(int argc, char** argv) {
      char* file_name = NULL;
      int offset = 0;
      char* type = "int32";
      int big_endian = 0;
    
      int i;
      for(i = 1; i < argc; i++) {
        if(!strncmp("-o", argv[i], 2)) {
          ++i;
          sscanf(argv[i], "%d", &offset);
        } else if(!strncmp("-t", argv[i], 2)) {
          ++i;
          type = argv[i];
        } else if(!strncmp("-e", argv[i], 2)) {
          ++i;
          big_endian = !strncmp("big", argv[i], 3);
        } else {
          file_name = argv[i];
          break;
        }
      }
    
      if (i < argc - 1) {
        fprintf(stderr, "Ignoring extra arguments: ");
        ++i;
        for (; i < argc; i++) {
          fprintf(stderr, "%s ", argv[i]);
        }
        fprintf(stderr, "\n");
      }
    
      if (file_name == NULL) {
        fprintf(stderr, "Syntax: readint [-o offset] [-t type] [-e endian] <filename>\n"
          "Where:\n"
          "  type      'uint32', 'uint64', 'int32' (default), 'int64'.\n"
          "  endian    'big' or 'little' (default).\n"
          "  offset    offset in a file from where the read will happen, default is 0.\n"
        );
        return -1;
      }
    
      FILE* fp = fopen(file_name, "rb");
    
      if (fp == NULL) {
        fprintf(stderr, "Could not open the file: %s\n", file_name);
        return -1;
      }
    
      fseek(fp, offset, SEEK_SET);
    
      if (!strncmp("uint32", type, 6)) {
        uint32_u u;
        fread(u.array, sizeof(u.array), 1, fp);
        if (big_endian ^ sys_big_endian())
          swap(u.array, sizeof(u.array));
        printf("%u\n", u.val);
      } else if (!strncmp("int32", type, 5)) {
        int32_u u;
        fread(u.array, sizeof(u.array), 1, fp);
        if (big_endian ^ sys_big_endian())
          swap(u.array, sizeof(u.array));
        printf("%d\n", u.val);
      } else if (!strncmp("uint64", type, 6)) {
        uint64_u u;
        fread(u.array, sizeof(u.array), 1, fp);
        if (big_endian ^ sys_big_endian())
          swap(u.array, sizeof(u.array));
        printf("%"PRIu64"\n", u.val);
      } else if (!strncmp("int64", type, 5)) {
        int64_u u;
        fread(u.array, sizeof(u.array), 1, fp);
        if (big_endian ^ sys_big_endian())
          swap(u.array, sizeof(u.array));
        printf("%"PRId64"\n", u.val);
      } else {
        printf("Unknown type: %s\n", type);
      }
    
      fclose(fp); 
      return 0;
    }
    

    然后这样做:

    gcc -o readint readint.c
    sudo mv readint /usr/local/bin
    

    现在您有了一个名为“readint”的便捷工具,其语法如下:

    readint [-o offset] [-t int32|uint32|int64|uint64 ] [-e little|big ] <filename>
    

    【讨论】:

      【解决方案4】:

      您可以在网上搜索模块来解释 MOI 文件(Perl 或 Python)。否则,我真的不认为您可以像从二进制文件中那样获取日期,因为如果您查看内部,它实际上是“垃圾”,因为它是二进制文件。尽管您也可以尝试使用 strings 命令查看是否有与日期匹配的清晰字符串

      【讨论】:

        猜你喜欢
        • 2014-10-26
        • 2011-05-26
        • 2016-04-02
        • 2013-07-14
        • 2023-03-13
        • 2013-08-26
        • 1970-01-01
        • 2022-05-30
        • 1970-01-01
        相关资源
        最近更新 更多