Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 04/10/2012, à 10:11

obibann

[Résolu] Remplacement dans un fichier sans fichier temporaire

Bonjour,

Je cherche à remplacer une chaine par une autre dans un fichier. Jusque là, rien de compliqué, sauf j'ai une contrainte de taille : le fichier pèse 4Go.

Ceci implique que je ne peux pas me permettre de passer par un fichier temporaire pour des questions de performance.

Pour le moment, j'utilise sed comme ceci :

sed -i "s/chaine_a_remplacer/nouvelle_chaine/" mon_fichier

Cependant, "sed -i" utilise implicitement un fichier temporaire, donc le problème reste entier...

N'existe-t-il pas une commande permettant de modifier un fichier directement ?

Merci

Dernière modification par obibann (Le 05/10/2012, à 16:24)


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#2 Le 04/10/2012, à 17:19

aduxas

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Je ne pense pas que ce que tu veux soit physiquement possible.  Que se passerait-il si tu insère du texte, ou si la nouvelle chaine est plus longue que la chaine a remplacer?  Tout garder en mémoire jusqu'à la fin ne marcherait pas non plus:  c'est l'OS qui la gère.

Hors ligne

#3 Le 05/10/2012, à 05:37

nesthib

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

C'est tout à fait possible, par exemple avec dd. Cependant, comme le fait remarquer aduxas, il faut que la modification fasse le même nombre de bits, sinon il faut récrire le fichier.


GUL Bordeaux : GirollServices libres : TdCT.org
Hide in your shell, scripts & astuces :  applications dans un tunnelsmart wgettrouver des pdfinstall. auto de paquetssauvegarde auto♥ awk
  ⃛ɹǝsn xnuᴉꞁ uʍop-ǝpᴉsdn

Hors ligne

#4 Le 05/10/2012, à 10:11

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

La chaine à remplacer ne fait pas forcement le même nombre de bits.
Je remplace un marqueur par sa valeur.

MD5SUM="[MD5SUM]"

devient

MD5SUM="6a5bc1cc5f80a48b540bc09d082b5855"

Le but étant de construire mon fichier puis d'y stocker son hash pour des vérifications lors de son utilisation.

Dans un langage de programmation, je pourrais faire un "fopen", localiser ma ligne qui se trouve dans les premières du fichier, "fwrite" pour réécrire ma ligne, "fclose" pour ferme le fichier. Dans ce cas là, je ne pense pas que le fichier soit entièrement réécrit.

Pourquoi celà n'est-il pas possible avec des commandes Linux ?

Pour dd, je peux réserver le nombre de bits qu'il faut, car je connais par avance la longueur d'une chaine md5. Il faudrait cependant connaitre le bit auquel ma chaine doit commencer. Comment je peux trouver cette information ? Grep le permet-il ?

grep -b "^MD5SUM=" mon_script.sh | cut -d":" -f1

C'est correct ?

Et pour dd, je procède comment, comme ceci ?

dd if="MD5SUM=blablalba" of=mon_script.sh bs=1 seek=`grep -b "^MD5SUM=" mon_script.sh | cut -d":" -f1`

Merci

Dernière modification par obibann (Le 05/10/2012, à 10:22)


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#5 Le 05/10/2012, à 13:34

Totor

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

le fopen chargera le fichier en mémoire et comme il est peut probable que tu aies 4Go de mémoire libre, le système utilisera un fichier temporaire ....


-- Lucid Lynx --

Hors ligne

#6 Le 05/10/2012, à 13:50

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Totor a écrit :

le fopen chargera le fichier en mémoire et comme il est peut probable que tu aies 4Go de mémoire libre, le système utilisera un fichier temporaire ....

Non, fopen attribut un pointeur vers le fichier et ne charge pas tout le fichier en mémoire.
Les données écrites sont stockées en mémoire puis écrite physiquement dans le fichier sans réécrire l'intégralité du fichier. Ces fonctions ne modifient que les blocs nécessaires dans le fichier, non l'intégralité du fichier.

Le seul cas probable où le système devra stocker tout le fichier, c'est si l'on souhaite modifier la dernière ligne. Mais ce n'est pas mon cas, la ligne à modifier se trouve parmi les premières lignes de mon fichier.

Dernière modification par obibann (Le 05/10/2012, à 13:53)


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#7 Le 05/10/2012, à 14:01

compte supprimé

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

obibann a écrit :

La chaine à remplacer ne fait pas forcement le même nombre de bits.
Je remplace un marqueur par sa valeur.

MD5SUM="[MD5SUM]"

devient

MD5SUM="6a5bc1cc5f80a48b540bc09d082b5855"

Le but étant de construire mon fichier puis d'y stocker son hash pour des vérifications lors de son utilisation.

Ca veut dire que pour vérifier l'intégrité de ton fichier, tu fais l'opération inverse : lecture du md5sum stocké dans le fichier, le replacer par le pattern initial et calculer la somme md5 sur le fichier ?
L'idéal est de rajouter les octets md5sum en fin de fichier dans ce cas.

#8 Le 05/10/2012, à 14:18

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Ce n'est pas tout à fait ça. Mon fichier final contient une partie bash, puis une partie binaire.
Le hash stocké dans la partie bash correspond au hash de la partie binaire.

La partie bash sert à extraire automatiquement le binaire, puis à déployer son contenu (il s'agit d'un tar.gz).
Il fait également tout un tas d'autres choses tongue.

Actuellement, je créé mon tar.gz, je md5sum, je stock le hash dans le fichier sh, puis je rassemble le tout.
Ce que je souhaiterai, c'est éviter de passer par une archive intermédiaire et de créer mon tar.gz directement à la suite de mon sh (je divise ainsi par 2 les temps de création).

Cependant, en faisant comme ça je suis obligé de stocker mon hash dans le fichier final qui est gros, d'où mon problème de fichier temporaire.


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#9 Le 05/10/2012, à 14:48

compte supprimé

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Ajouter le md5sum en fin du bash+archive est peut être plus pratique. Tu sais combien d'octets tu écris en fin et donc tu sais les virer pour decompresser. A la création c'est juste un append au fichier bash+tar.gz et donc il faut juste caluler la somme sur le fichier total bash+tar.gz.

#10 Le 05/10/2012, à 14:52

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

alduc1 a écrit :

Ajouter le md5sum en fin du bash+archive est peut être plus pratique. Tu sais combien d'octets tu écris en fin et donc tu sais les virer pour decompresser. A la création c'est juste un append au fichier bash+tar.gz et donc il faut juste caluler la somme sur le fichier total bash+tar.gz.

Oui mais dans ce cas, ma variable n'est plus déclarée en début de script, je ne peut donc plus récupérer sa valeur.

Pour info, j'ai fait un test de lecture séquentielle en PHP (pour aller vite) et ça marche parfaitement. La modification de ma ligne est instantanée car je ne lit que 20 lignes, modifie 1 ligne ensuite je m'arrête.

Au pire, si je ne trouve pas d'autres solutions, je serais obligé de faire un petit programme C... Mais c'est dommage d'en arriver là tongue

On m'a proposé de le faire avec dd, mais je ne trouve pas comment.

Dernière modification par obibann (Le 05/10/2012, à 14:53)


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#11 Le 05/10/2012, à 15:17

compte supprimé

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

obibann a écrit :

Oui mais dans ce cas, ma variable n'est plus déclarée en début de script, je ne peut donc plus récupérer sa valeur.

En recuperant la taille totale, tu peux recuperer la somme en fin, au moins en C.
Sinon en laissant exactement la place (MD5SUM="[MD5SUMMD5SUMMD5SUMMD5SUMMD5SUM]") pour l'insérer sans modifier la taille du fichier ?

#12 Le 05/10/2012, à 15:21

pingouinux

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

olibann #10 a écrit :

On m'a proposé de le faire avec dd, mais je ne trouve pas comment.

Voici un exemple :

$ cat mon_bash
#!/bin/bash

# Début du fichier bash

MD5SUM="00000000000000000000000000000000"

# Suite du fichier bash
dd if=<(echo -n 6d2bf9d6ebe32f56c7ab8bdbb53d1e9f) of=mon_bash bs=1 seek=47 conv=notrunc
$ cat mon_bash
#!/bin/bash

# Début du fichier bash

MD5SUM="6d2bf9d6ebe32f56c7ab8bdbb53d1e9f"

# Suite du fichier bash

Hors ligne

#13 Le 05/10/2012, à 16:15

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Super !!! Ça fonctionne à merveille.

Pour localiser la ligne :

head -n50 mon_bash | grep -b "^MD5SUM="

Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#14 Le 05/10/2012, à 16:39

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Bon par contre, la commande dd ne veut pas s’exécuter dans un fichier bash...


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#15 Le 05/10/2012, à 16:46

pingouinux

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Comment as-tu lancé le script ? Il doit être lancé en bash, pas en sh.

Hors ligne

#16 Le 05/10/2012, à 16:56

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

#!/bin/bash
[...]
md5sum=`sed -e '1,/^'$BIN_SEPARATOR'$/d' "$FINAL_NAME" | md5sum - | awk '{print $1}'`
md5byte=`head -n200 "$FINAL_NAME" | grep -b "^MD5SUM=" | cut -d":" -f1`
dd if=<(echo -n MD5SUM=$md5sum) of=$FINAL_NAME bs=1 seek=$md5byte conv=notrunc
ddcommand="dd if=<(echo -n MD5SUM=$md5sum) of=$FINAL_NAME bs=1 seek=$md5byte conv=notrunc"
eval $ddcommand
dd if=<(echo -n MD5SUM=c7f0b9dfd40da9561253983c0ecc044f) of=webEnv_uninstall_1000.bin bs=1 seek=615 conv=notrunc

Les 3 méthodes pour le dd échouent :

dd: opening `<(echo -n MD5SUM=9d850edb583a8b36c1f9dc3bbcd51c7f)': No such file or directory

Par contre, si je lance la commande (avec ou sans variables) directement dans le terminal, ça fonctionne...


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#17 Le 05/10/2012, à 17:02

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

En passant par un fichier temporaire ça marche :

echo -n "MD5SUM=$md5sum" > /tmp/md5sum
dd if=/tmp/md5sum of=$FINAL_NAME bs=1 seek=$md5byte conv=notrunc
rm -f /tmp/md5sum

Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#18 Le 05/10/2012, à 17:17

pingouinux

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Quelle est ta version de bash ?

$ bash --version
GNU bash, version 4.2.24(1)-release (x86_64-pc-linux-gnu)

Hors ligne

#19 Le 05/10/2012, à 17:24

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne

#20 Le 05/10/2012, à 17:39

pingouinux

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Chez moi, les 3 formes que tu as utilisées en #16 fonctionnent dans un script bash.

Hors ligne

#21 Le 08/10/2012, à 07:53

obibann

Re : [Résolu] Remplacement dans un fichier sans fichier temporaire

Peut être le bash que j'utilise est buggée... Mon script est destiné à tourner sous RedHat EL 6.2 (ou CentOS 6.2).
Du coup, je garde la méthode via le petit fichier temporaire, dans le lequel je stocke le contenu du hash. Là, "if" ne m'engueule plus ^^

A ce stade, le résultat obtenu me convient parfaitement. Les temps de génération sont divisés par deux c'est parfait.

Merci pour votre aide.


Ubuntu 16.04
Avec Windows, on fait ce qu'on peut... Avec Linux, on fait ce qu'on veut !! :p

Hors ligne