Bash 脚本 - 读取二进制文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1972222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 21:30:33  来源:igfitidea点击:

Bash Script - Read Binary File

bashscriptingbinaryfiles

提问by Joel

I'm new to scripting, but I have a lot of experience programming in languages such as C# and Java.

我不熟悉脚本,但我有很多使用 C# 和 Java 等语言进行编程的经验。

I have a file that contains binary data. I want to write a Bash script that reads the year, month, and day contained in that file so I can sort the associated MOD files into folders according to the date they were recorded. I'm having trouble finding a way to read binary data and parsing it in a bash script. Is there any way to do this?

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

回答by R Samuel Klatchko

You can use od (plus head and awk for a little post-processing) for this. To get the year:

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

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

For the month:

本月:

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

And the day:

那天:

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

回答by Amirshk

I would recommend using python for this.

我建议为此使用python。

However, if you insist on bash, i would try using either sedin binary mode (never tried it) or using ddfor extracting specific bytes and then convert them.

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

回答by Stanislav Vitvitskyy

If this is not too hardcore for you I suggest compiling the following C-language program:

如果这对你来说不是太难,我建议编译以下 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;
}

Then do this:

然后这样做:

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

Now you have a handy tool called 'readint' with the following syntax:

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

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

回答by ghostdog74

you can search the net for modules to interpret MOI files (either Perl or Python). Otherwise, i don't really think you can get the date just like that from the binary file because if you look inside, its really "garbage" since its binary. Although you may also give the strings command a try to see if there are legible strings that match the date

您可以在网络上搜索模块来解释 MOI 文件(Perl 或 Python)。否则,我真的不认为你可以从二进制文件中得到这样的日期,因为如果你看看里面,它真的是“垃圾”,因为它是二进制文件。虽然您也可以尝试使用 strings 命令查看是否有与日期匹配的清晰字符串