Bash 脚本 - 读取二进制文件

发布于 2024-08-15 18:50:30 字数 254 浏览 9 评论 0原文

我是脚本编写新手,但在使用 C# 和 Java 等语言进行编程方面拥有丰富的经验。

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

I'm new to scripting, but I have a lot of experience programming in languages such as C# and 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

╰ゝ天使的微笑 2024-08-22 18:50:30

为此,您可以使用 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}')

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

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

For the month:

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

And the day:

day=$(od -t x1 --skip-bytes=9 --read-bytes=1 file.moi | head -1 | awk '{print $2}')
才能让你更想念 2024-08-22 18:50:30

我建议使用 python 来实现这一点。

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

I would recommend using python for this.

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

鹿港巷口少年归 2024-08-22 18:50:30

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

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

#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 [-o offset] [-t int32|uint32|int64|uint64 ] [-e little|big ] <filename>
安人多梦 2024-08-22 18:50:30

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文