2009-12-29 46 views
6

Soy nuevo en scripting, pero tengo mucha experiencia en programación en lenguajes como C# y Java.Bash Script - Leer archivo binario

Tengo a file that contains binary data. Quiero escribir un script Bash que lea el año, el mes y el día contenidos en ese archivo para que pueda ordenar los archivos MOD asociados en carpetas de acuerdo con la fecha en que se grabaron. Tengo problemas para encontrar una forma de leer datos binarios y analizarlos en un script bash. ¿Hay alguna manera de hacer esto?

+0

por curiosidad, ¿por qué bash y no perl/python? – Amirshk

+2

No hay razón realmente. Ya escribí un archivo BASH para cambiar el nombre de los archivos y moverlos. Entonces pensé que sería mejor ordenarlos por cuándo se grabaron los archivos y no cuando los copié de la cámara. – Joel

Respuesta

8

Puede usar od (más head y awk para un poco de postprocesamiento) para esto. Para obtener el año:

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

Para el mes:

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

Y al día:

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

funciona muy bien. Gracias. De hecho, encontré una forma mejor de obtener la fecha de los archivos que analizar los datos binarios antes de leer esto. Pero este código hace lo que se supone que debe hacer. ¡Gracias! – Joel

2

Recomendaría usar Python para esto.

Sin embargo, si insistes en bash, probaría usando sed en modo binario (nunca lo intenté) o usando dd para extraer bytes específicos y luego convertirlos.

0

se puede buscar en la red para los módulos de interpretar los archivos de MOI (ya sea Perl o Python) De lo contrario, realmente no creo que puedas obtener la fecha exactamente así del archivo binario porque si miras adentro, es realmente "basura" ya que es binario. Aunque también se puede dar a las cadenas de comandos una oportunidad para ver si hay cadenas legibles que responden a la fecha

1

Si esto no es demasiado duro para usted le sugiero compilar el siguiente programa en lenguaje 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; 
} 

a continuación, haga lo siguiente:

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

Ahora usted tiene una herramienta muy útil llamada 'readInt' con la siguiente sintaxis:

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