2009-12-29 8 views
6

Je suis novice en matière de programmation, mais j'ai beaucoup d'expérience en programmation dans des langages tels que C# et Java.Bash Script - Lire le fichier binaire

J'ai a file that contains binary data. Je veux écrire un script Bash qui lit l'année, le mois et le jour contenus dans ce fichier afin que je puisse trier les fichiers MOD associés dans des dossiers en fonction de la date à laquelle ils ont été enregistrés. Je n'arrive pas à trouver un moyen de lire les données binaires et de les analyser dans un script bash. Est-ce qu'il y a un moyen de faire ça?

+0

par curiosité, pourquoi bash et pas perl/python? – Amirshk

+2

Aucune raison vraiment. J'ai déjà écrit un fichier BASH pour renommer les fichiers et les déplacer. Ensuite, j'ai pensé qu'il serait préférable de les trier par quand les fichiers ont été enregistrés plutôt que par quand je les ai copiés de l'appareil photo. – Joel

Répondre

8

Vous pouvez utiliser od (plus head et awk pour un petit post-traitement) pour cela. Pour obtenir l'année:

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

Pour le mois:

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

Et le jour:

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

fonctionne très bien. Merci. En fait, j'ai trouvé un meilleur moyen d'obtenir la date à partir des fichiers que d'analyser les données binaires avant de lire ceci. Mais ce code fait ce qu'il est censé faire. Merci! – Joel

2

Je recommanderais d'utiliser python pour cela.

Cependant, si vous insistez sur bash, j'essayerais d'utiliser sed en mode binaire (jamais essayé) ou en utilisant dd pour extraire des octets spécifiques, puis les convertir.

0

vous pouvez chercher sur le net pour les modules d'interpréter les fichiers MOI (soit Perl ou Python). Sinon, je ne pense pas vraiment que vous pouvez obtenir la date juste comme ça depuis le fichier binaire, car si vous regardez à l'intérieur, c'est vraiment "garbage" depuis son binaire. Bien que vous pouvez également donner les cordes commande un essai pour voir s'il y a des chaînes lisibles qui correspondent à la date

1

Si ce n'est pas trop hardcore pour vous, je suggère de compiler le programme C-langue suivante:

#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; 
} 

ensuite, faites ceci:

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

maintenant vous avez un outil pratique appelé 'readInt' avec la syntaxe suivante:

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