Comment puis-je changer le code ^ L dans de nombreux fichiers dans Ubuntu?

8

J'ai beaucoup de fichiers XML, plus de 50000 d'entre eux.

Dans certains fichiers XML, certains fichiers sont écrits comme ceci

<filename>abc.JPEG<^Lilename>

^Lest juste un caractère, mais je ne trouve pas ce que ^Lsignifie Google.

Lorsque j'utilise catpour imprimer le contenu d'un fichier, il s'affiche comme suit

<filename>abc.JPEG<
                   ilename>

Quoi qu'il en soit, je veux passer <filename>abc.JPEG<^Lilename>à<filename>abc.JPEG</filename>

J'ai déjà trouvé une commande pour changer un mot dans de nombreux fichiers, tels que

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

Mais cette commande ne fonctionne pas dans mon cas, car elle ne peut pas reconnaître le mot recherché lorsque je tape juste ^L.

Comment puis - je changer <filename>abc.JPEG<^Lilename>pour <filename>abc.JPEG</filename>de nombreux fichiers?

Yang
la source
6
Apparemment, quelqu'un a utilisé <\filename>plutôt que </filename>dans un contexte où \fserait interprété comme le caractère de flux de formulaire. Vous devriez probablement retrouver la source de ces fichiers et signaler le problème avec leur outil de génération au développeur. Pour réparer les fichiers, la réponse acceptée est très bien.
Hans-Martin Mosner du

Réponses:

17

Control-L (représenté par ^L) est le caractère "saut de page". En ASCII, il a la valeur décimale 12 ( Lest la 12e lettre de l'alphabet) ou la valeur hexadécimale 0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

Vous pouvez le remplacer à l'aide d'outils comme sed en spécifiant le code d'échappement hexadécimal:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

Alternativement, composez ^Ldirectement en utilisant la séquence de clavier CTRL+ V CTRL+L

sed 's/CTRL+VCTRL+L//'

Pour votre remplacement spécifique, étant donné

$ printf '<\x0cilename\n'
<
 ilename

puis

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

(le gmodificateur est ajouté dans le cas où il y a plus d'une instance par ligne).

tournevis
la source
Dans mon cas, "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" ne fonctionne pas. Mais, selon votre réponse, "$ find. -Exec perl -pi -e's / <\ x0cilename> / <\ / filename> / g '{} \;" fonctionne bien. Merci pour votre réponse :)
Yang
@Yang désolé, je viens de réaliser que j'ai confondu la barre oblique et la barre oblique inversée dans ma réponse (corrigée maintenant) - je ne sais toujours pas pourquoi cela aurait empêché la version sed de fonctionner
steeldriver
Une très bonne réponse! Ce serait encore mieux s'il incluait un findqui faisait une boucle sur ces 50000 fichiers XML et les traitait automatiquement (et faisait également une sauvegarde).
Kingsley
2

Comme le souligne Hans-Martin Mosner dans les commentaires, il semble que quelqu'un ait utilisé des barres obliques inverses au lieu de barres obliques lors de la génération du XML (ou peut-être exécuté toute la <filename>section via un convertisseur Unix-vers-Windows qui était trop zélé pour les barres obliques). \fest une séquence d'échappement rarement utilisée pour un caractère de saut de page, alias U + 0C ou ^ L. Ainsi, une étape ultérieure du pipeline a ensuite remplacé le \fpar des caractères littéraux U + 0C.

Heureusement, U + 0C est un caractère extrêmement rare qui ne sera probablement pas trouvé intentionnellement dans n'importe quel type de XML. Et puisque seulement \fproduirait ce, par opposition à ( par exemple) \gou \k, une découverte et remplacement universel devrait fixer non seulement , </filename>mais aussi </folder>, </file>ou toute autre chose qui a obtenu estropié.

C'est ce que fait le script sed de steeldriver; Je ferais juste un peu plus général:

sed 's|\x0c|/f|g'

Cela signifie "(s) wap toutes les instances de \x0c(c'est-à-dire, U + 0C) à /f, (g) lobalement".

Draconis
la source
2

\fest le caractère de flux de formulaire en Perl. Il semble que ces fichiers mal formés aient été créés par quelqu'un de nouveau à Perl et XML.

Voici un correctif beaucoup plus Perlier - qui répond également aux objectifs du PO d'automatiser la mise à jour de tous les fichiers, contrairement à la réponse acceptée avec sed, qui ne fonctionnera que sur un fichier à la fois car il n'est pas associé find.

\fpeut simplement être utilisé lui-même au lieu du code hexadécimal x0c.

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

Ici, j'ai ajouté -type fà tel findpour ne renvoyer que des fichiers simples - sinon, findil reviendra .dans la liste et déclenchera un avertissement lorsque vous essayez de le modifier, bien que tout le reste fonctionne.

J'ai également rendu l'expression plus facile à voir en utilisant le xdrapeau qui ignore les espaces blancs réels, vous permettant d'espacer les éléments de votre expression régulière. Si vous n'aimez pas ça, le voici sans:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

Et dans le cas probable où tous les caractères de flux de formulaire sont faux et tous devraient être remplacés par /f, alors vous pouvez affiner encore plus le one-liner:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

Vous n'avez pas besoin d'utiliser des barres obliques pour entourer les éléments de votre commande de substitution de regex ( s///) en Perl. Vous pouvez utiliser n'importe quel symbole. Si vous choisissez d'utiliser n'importe quel type de symbole en forme de parenthèse, cependant, vous devez utiliser les deux: s[old][new]par exemple.

Comme je n'utilise pas de barres obliques, je n'ai pas à échapper à aucune barre oblique.

Quant à -i.bkp: perl -pi -evous permet de modifier sur place - mais si vous voulez une assurance supplémentaire au cas où vous auriez mal votre programme de recherche et remplacement Perl, vous pouvez mettre une extension de fichier afin qu'il fasse une copie des fichiers originaux pour vous. Ici, je l'ai utilisé .bkp.

Dans les versions les plus récentes de Perl, l'édition sur place a été mise à jour pour être plus résistante au cas où votre système souffrirait également d'un problème grave comme une panne de courant ou un manque d'espace disque. Voici l'auteur de Perl, Brian D Foy, sur l'amélioration de l'édition in situ dans les Perls récents.

Vous devriez envisager d'utiliser Perl pour ce type de tâches, car il s'agit d'un langage de programmation à usage général extrêmement puissant mais sous-évalué, dont l'un des objectifs de conception d'origine était de remplacer sedet awkavec quelque chose de bien meilleur.

Les capacités de correspondance regex de Perl 5 et la syntaxe regex améliorée dépassent de loin celles de sed, awket en fait tous les autres langages de programmation à part Perl 6, faisant de Perl le choix le plus judicieux pour les manipulations regex simples et avancées.

Pour clarifier: sedfonctionnera bien findaussi et vous pouvez également utiliser sed -i.bkppour faire une sauvegarde de chaque fichier modifié, mais pour autant que je sache, il ne dispose pas de la résilience supplémentaire dans Perl 5.28 et supérieur. Il utilise également la syntaxe regex UNIX ® traditionnelle plus maladroite et beaucoup moins puissante.

Medlock Perlman
la source