2 votes

sed : Suppression de \r\r antes de \n dans un très gros fichier

J'ai un fichier d'image disque corrompu (environ 27 Go) dans lequel, avant que tous les fichiers de l'image disque ne soient effacés, il n'y a pas eu d'erreur. \n caractères \r\r a été inséré. Je veux supprimer ces \r\r avant tout \n.

J'ai essayé avec awk :

awk '{ sub("\r\r$", ""); print }' mangled.raw > image.raw

Mais le fichier semble trop volumineux : "awk : run time error : out of memory"

J'ai aussi essayé avec sed :

sed 's/\r\r$//g' mangled.raw > image.raw

Mais ici le fichier de sortie semble incomplet : Il ne fait que 20 Go et la fin de mangled.raw contient beaucoup de caractères zéro alors que la fin de image.raw contient le contenu d'un fichier. D'une certaine manière, sed semble s'arrêter avant la fin.

Vous avez une idée de la façon de procéder ?

0 votes

Même si vous parvenez à faire fonctionner une commande sur un fichier de cette taille, vous êtes quasiment sûr de vous retrouver avec une image corrompue : à chaque endroit où il y avait initialement un ' \r\r\n ', le ' \r\r sera également supprimé. Dans les données binaires aléatoires, cette séquence est censée se produire une fois tous les 16 Mo, donc très likeky en 27GB.

0 votes

Dans mon fichier, chaque ' \n a été remplacé par \r\r\n '. Cela signifie qu'une séquence déjà existante de ' \r\r\n devient \r\r\r\r\n '. Un remplacement de ' \r\r\n par \n ' rétablit ainsi l'état initial.

0 votes

En effet, vous avez raison. Je me suis trompé.

3voto

Le commentaire d'Eldering est peut-être correct - cela dépend de la manière dont la corruption s'est produite. Si elle a fait l'équivalent de s/\n/\r\r\n/ alors c'est réversible, mais si c'est le cas s/\r*\n/\r\r\n/ alors ça ne l'est pas.

Dans tous les cas, j'utiliserais perl pour quelque chose comme ça. Contrairement à sed, il a été conçu dès le départ pour travailler avec des chaînes de caractères très longues et pouvant contenir des NULs et d'autres caractères non textuels.

perl -pe 's/\r\r\n/\n/g' mangled.raw > image.raw

Cela pourrait consommer beaucoup de mémoire puisque le fichier est toujours lu comme une série de lignes, et il pourrait y avoir de larges segments de fichier sans \n qui sera vu comme une seule "ligne". Mais si vous le lisez par blocs, vous devez faire attention à ne pas manquer une \r\r\n qui chevauche la limite d'un bloc. Comme ceci :

perl -e '
  $/=\65536;
  while(<>) {
    if(/\r\z/) {
      if(length($nextblock=<>)) {
        $_.=$nextblock;
        redo;
      }
    }
    s/\r\r\n/\n/g;
    print;
   }
' mangled.raw > image.raw

編集する。 J'ai réalisé que le code ci-dessus serait bloqué dans une boucle infinie si le dernier octet de l'entrée était \r . Il a été mis à jour pour gérer ce cas correctement.

Edit 2 : La ligne unique en perl contenait un caractère de remplacement incorrect. Il a été mis à jour.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X