Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Petite chirurgie sur fichiers binaires

14 réponses
Avatar
geo cherchetout
Bonjour,

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à xx999. Les 1,
2 ou 3 premiers octets de chacun de ces fichiers codent un nombre également
compris entre 1 et 999. (Un octet pour chaque chiffre, 30 pour 0, 31 pour 1,
etc.) Voici un échantillon :

$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
4 0xx010
84 xx011
243xx012
1 0xx013

Comment faire pour remplacer ces seuls premiers octets (toujours suivis d'un
espace puis d'un zéro) par les chiffres significatifs des noms de fichiers,
de telle façon que la même commande donne ceci :

7 0xx007
8 0xx008
9 0xx009
10 xx010
11 xx011
12 xx012
13 xx013

Je précise que l'opération inverse, que je saurais *peut-être* réaliser, ne
m'intéresse pas. Les noms de fichiers sont imposés.
Merci.

10 réponses

1 2
Avatar
Hugues
Ce cher geo cherchetout a dit :

Bonjour,

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à
xx999. Les 1, 2 ou 3 premiers octets de chacun de ces fichiers codent
un nombre également compris entre 1 et 999. (Un octet pour chaque
chiffre, 30 pour 0, 31 pour 1, etc.) Voici un échantillon :

$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
4 0xx010
84 xx011
243xx012
1 0xx013

Comment faire pour remplacer ces seuls premiers octets (toujours
suivis d'un espace puis d'un zéro) par les chiffres significatifs des
noms de fichiers, de telle façon que la même commande donne ceci :

7 0xx007
8 0xx008
9 0xx009
10 xx010
11 xx011
12 xx012
13 xx013



man dd

;)

--
Hugues Hiegel [http://www.hiegel.fr/~hugues/]
Avatar
Herve Autret
On Mon, 22 Mar 2010 18:56:34 +0100, geo cherchetout wrote:

Bonjour,

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à xx999.
$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
Comment faire pour remplacer ces seuls premiers octets (toujours suivis
d'un espace puis d'un zéro) par les chiffres significatifs des noms de
fichiers, de telle façon que la même commande donne ceci :
7 0xx007
8 0xx008
9 0xx009



Je fais souvent compliqué même quand c'est simple, note... Ceci dit,
j'écrirais un programe en C qui lit le fichier dont on lui passe le nom
en argument et écrit sur le flux de sortie.

Le pgm :
- ouvre le fichier
- le passe par un scanner flex qui reconnaît le motif du début,
- décode le chiffre après le xx et l'écrit dans le flux de sortie,
- écrit le 2eme champ en sortie
- laisser passer le reste du fichier sans filtrage.

Je l'utiliserais dans un script t.q :
$ mkdir -p result
$ for FILE in xx*; do pgm $FILE > result/FILE ; done

Mais bon, en perl on doit pouvoir règler ça de manière nettement plus
expéditive.
--
Hervé
Avatar
geo cherchetout
Le 22/03/2010 19:29, *Hugues* a écrit fort à propos :

man dd

;)



J'aurais du y penser ! Merci.

Toutefois je ne vois pas comment retenir seulement les chiffres
significatifs de mes noms de fichiers (sans les zéros qui précèdent) ni
comment remplacer seulement les octets précédant le premier espace sans
écraser celui-ci ni le multiplier. D'autres pages de man ?
Avatar
geo cherchetout
Le 22/03/2010 19:54, *Herve Autret* a écrit fort à propos :

Je fais souvent compliqué même quand c'est simple, note... Ceci dit,
j'écrirais un programe en C qui lit le fichier dont on lui passe le nom
en argument et écrit sur le flux de sortie.

Le pgm :
- ouvre le fichier
- le passe par un scanner flex qui reconnaît le motif du début,
- décode le chiffre après le xx et l'écrit dans le flux de sortie,
- écrit le 2eme champ en sortie
- laisser passer le reste du fichier sans filtrage.

Je l'utiliserais dans un script t.q :
$ mkdir -p result
$ for FILE in xx*; do pgm $FILE > result/FILE ; done



C'est fou ce qu'il est difficile de faire faire à un programme ce que
n'importe qui peut faire sans effort avec un éditeur hexadécimal !
Je retiens quand-même le schéma pour ma prochaine vie. Merci.

Mais bon, en perl on doit pouvoir règler ça de manière nettement plus
expéditive.



0,001% du problème est déjà résolu, je reprends espoir. :) Il ne me reste
plus qu'à étudier Perl ou attendre que quelqu'un se dévoue...
Avatar
Herve Autret
geo cherchetout :

Je fais souvent compliqué même quand c'est simple, note...


Je retiens quand-même le schéma pour ma prochaine vie. Merci.



J'avais un peu prévenu, hein...
Avatar
Benoit Izac
Bonjour,

le 22/03/2010 à 18:56, geo cherchetout a écrit dans le message
<4ba7af07$0$17868$ :

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à xx999.
Les 1, 2 ou 3 premiers octets de chacun de ces fichiers codent un
nombre également compris entre 1 et 999. (Un octet pour chaque
chiffre, 30 pour 0, 31 pour 1, etc.) Voici un échantillon :


^^^^^^^^^^^^^^^^^^^^^^^^^^
Je ne comprends pas ce passage.

$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
4 0xx010
84 xx011
243xx012
1 0xx013

Comment faire pour remplacer ces seuls premiers octets (toujours
suivis d'un espace puis d'un zéro) par les chiffres significatifs des
noms de fichiers, de telle façon que la même commande donne ceci :

7 0xx007
8 0xx008
9 0xx009
10 xx010
11 xx011
12 xx012
13 xx013

Je précise que l'opération inverse, que je saurais *peut-être*
réaliser, ne m'intéresse pas. Les noms de fichiers sont imposés.



Non testé :

for f in xx*; do
n=$(printf '%d' "${f#xx}")
sed -e "1s/^[0-9][0-9]* /$n /" <"$f" >"$f.tmp"
#mv "$f.tmp" "$f"
done

Après avoir vérifié, tu pourras virer le « # ».

--
Benoit Izac
Avatar
Fabien LE LEZ
On Mon, 22 Mar 2010 18:56:34 +0100, geo cherchetout :

Un octet pour chaque chiffre, 30 pour 0



"30" sans autre indication, ça signifie "30 décimal".
Le caractère '0' a pour code ASCII 48, ou 0x30.

Comment faire pour remplacer ces seuls premiers octets (toujours suivis d'un
espace puis d'un zéro) par les chiffres significatifs des noms de fichiers,
de telle façon que la même commande donne ceci :



Si je comprends bien, le fichier xx102 peut contenir
64 0abcdef
et doit, après traitement, contenir
102 0abcdef

Je ne sais pas faire ça in-situ. Par contre, créer les fichiers
corrigés dans un autre répertoire, c'est relativement simple :

- ouvrir un fichier
- ignorer le premier nombre
- mettre dans le fichier-destination, le nombre contenu dans le nom de
fichier
- recopier tous les octets suivants (c'est-à-dire, à partir de
l'espace) sans modification.


Voici du code C++ qui devrait faire à peu près ce que tu veux. Il est
très long, parce que le C++ est un langage passablement verbeux.


Mets ça dans un fichier truc.cpp, puis tape
g++ truc.cpp

Notes :

- Il faut créer un sous-répertoire "dest" (vide) dans le répertoire
courant.
- Le programme lit tous les fichiers un par un, de xx001 à xx999. Si
un fichier manque, il s'arrête immédiatement. Tu peux modifier ce
comportement en remplaçant le premier "break" par "continue".


/////// début de truc.cpp

#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string>

using namespace std; // Don't do this at home, kids!

int main()
{
static string const repertoire_source= ".";
static string const repertoire_destination= "dest";

for (int i=1; i<™9; ++i)
{
// Calcul du nom de fichier
char nom_fichier[]= "xx000";
sprintf (nom_fichier, "xx%03d", i); /* Pas très fiable, mais
suffisant dans ce cas, et plus simple que la version "purement C++".
*/


// Ouverture des fichiers
string const nom_source= repertoire_source + "/" + nom_fichier;
ifstream ifs (nom_source.c_str());
if (!ifs)
{
cerr << "Ne peut lire " << nom_source << "n";
break;
}

string const nom_dest= repertoire_destination
+ "/" + nom_fichier;
ofstream ofs (nom_dest.c_str());
if (!ofs)
{
cerr << "Ne peut écrire " << nom_dest << "n";
break;
}


// On "avale" le premier entier, qui ne nous sert à rien.
int dummy;
ifs >> dummy;

// On met dans le fichier destination, le nombre i
ofs << i;

// Tout le reste est identique ; on recopie les octets
ofs << ifs.rdbuf();
}
}

/////// fin de truc.cpp
Avatar
Fabien LE LEZ
On Mon, 22 Mar 2010 22:08:21 +0100, Benoit Izac
:

chiffre, 30 pour 0, 31 pour 1, etc.) Voici un échantillon :


^^^^^^^^^^^^^^^^^^^^^^^^^^
Je ne comprends pas ce passage.



Il parlait en hexadécimal. Le code ASCII de '0' est 48, soit 0x30.
Avatar
Olivier Miakinen
Bonjour,

Le 22/03/2010 18:56, geo cherchetout a écrit :

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à xx999. Les 1,
2 ou 3 premiers octets de chacun de ces fichiers codent un nombre également
compris entre 1 et 999. (Un octet pour chaque chiffre, 30 pour 0, 31 pour 1,
etc.) Voici un échantillon :

$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
4 0xx010
84 xx011
243xx012
1 0xx013

Comment faire pour remplacer ces seuls premiers octets (toujours suivis d'un
espace puis d'un zéro)



Euh... il y a un problème soit dans la description, soit dans l'exemple,
parce que dans les 7 lignes ci-dessus il y en a une où le nombre (243)
n'est pas suivi par une espace, et quatre où l'espace n'est pas suivie
par un 0.

par les chiffres significatifs des noms de fichiers,
de telle façon que la même commande donne ceci :

7 0xx007
8 0xx008
9 0xx009
10 xx010
11 xx011
12 xx012
13 xx013



Idem ici : dans trois des cas où il n'y avait pas de 0 tu l'as rajouté,
alors que dans le dernier cas il a été supprimé.

Bon, je vais supposer que ton exemple aurait dû être le suivant.

Avant :
----------------------
81 0xx007
82 0xx008
83 0xx009
4 0xx010
84 0xx011
243 0xx012
1 0xx013
----------------------

Après :
----------------------
7 0xx007
8 0xx008
9 0xx009
10 0xx010
11 0xx011
12 0xx012
13 0xx013
----------------------

Je précise que l'opération inverse, que je saurais *peut-être* réaliser, ne
m'intéresse pas. Les noms de fichiers sont imposés.



Ok. Le plus gros problème ici, c'est que tu dis qu'il s'agit de fichiers
binaires, alors je ne sais pas si les outils traditionnels (sed, awk,
etc.) sont censés fonctionner (par exemple si tu as un trop grand nombre
de caractères entre deux n).

Note que ça ne coûte rien d'essayer la proposition de Benoît Izac. Mais
si jamais elle ne fonctionnait pas, soit tu fais une usine à gaz à base
de « head -c N » et « tail -c +N », soit tu suis le conseil d'Hervé
Autret (un programme en C).

--
Olivier Miakinen
Avatar
Benoit Izac
Bonjour,

le 22/03/2010 à 22:46, Olivier Miakinen a écrit dans le message
<4ba7e51b$ :

Mon shell est bash. J'ai 999 fichiers binaires nommés xx001 à xx999.
Les 1, 2 ou 3 premiers octets de chacun de ces fichiers codent un
nombre également compris entre 1 et 999. (Un octet pour chaque
chiffre, 30 pour 0, 31 pour 1, etc.) Voici un échantillon :

$ for i in xx*; do head -c3 $i; ls $i; done
81 xx007
82 xx008
83 xx009
4 0xx010
84 xx011
243xx012
1 0xx013

Comment faire pour remplacer ces seuls premiers octets (toujours
suivis d'un espace puis d'un zéro)



Euh... il y a un problème soit dans la description, soit dans l'exemple,
parce que dans les 7 lignes ci-dessus il y en a une où le nombre (243)
n'est pas suivi par une espace, et quatre où l'espace n'est pas suivie
par un 0.



Ça, tu ne peux pas le dire car tu ne vois que les 3 premiers octets de
chaque fichier (head -c3).

[...]
Ok. Le plus gros problème ici, c'est que tu dis qu'il s'agit de fichiers
binaires, alors je ne sais pas si les outils traditionnels (sed, awk,
etc.) sont censés fonctionner (par exemple si tu as un trop grand nombre
de caractères entre deux n).



GNU sed n'a pas de limite (voir « GNU `sed''s Limitations and
Non-limitations » dans la page info.

Selon POSIX, la taille des lignes pour les utilitaires qui traitent du
texte ne devrait pas dépasser LINE_MAX octets (minimum 2048).

--
Benoit Izac
1 2