2009-12-29 214 views
6

我不熟悉腳本,但我有很多使用C#和Java等語言編程的經驗。Bash腳本 - 讀取二進制文件

我有a file that contains binary data。我想寫一個Bash腳本來讀取該文件中包含的年份,月份和日期,以便根據記錄的日期將相關的MOD文件分類到文件夾中。我無法找到讀取二進制數據並在bash腳本中解析它的方法。有沒有辦法做到這一點?

+0

出於好奇,爲什麼bash而不是perl/python? – Amirshk 2009-12-29 00:09:53

+2

沒有理由。我已經寫了一個BASH文件來重命名文件並移動它們。然後我認爲最好是在記錄文件時對它們進行排序,而不是將它們從相機上覆制下來。 – Joel 2009-12-29 00:24:49

回答

8

你可以使用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}') 
+0

效果很好。謝謝。實際上,在閱讀本文之前,我發現了一種更好的方法來從文件中獲取日期,而不是解析二進制數據。但是這段代碼確實做了它應該做的。謝謝! – Joel 2009-12-29 01:49:06

2

我會建議使用python。但是,如果你堅持使用bash,我會嘗試在二進制模式下使用sed(從未嘗試過)或使用dd來提取特定字節,然後轉換它們。

0

您可以搜索網上的模塊來解釋MOI文件(或Perl或Python )。否則,我真的不認爲你可以像從二進制文件那樣得到日期,因爲如果你從裏面看,它真的是「垃圾」,因爲它的二進制文件。雖然你也可以給strings命令一試,看是否有匹配的日期

1

是清晰可辨的字符串。如果這不是太鐵桿你,我建議編譯下面的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>