Come posso cambiare il codice ^ L in molti file in Ubuntu?


8

Ho molti file XML, oltre 50000.

In alcuni file XML, alcuni file sono scritti in questo modo

<filename>abc.JPEG<^Lilename>

^Lè solo un personaggio, ma non riesco a trovare cosa ^Lsignifichi con Google.

Quando uso catper stampare il contenuto di un file, si presenta come il seguente

<filename>abc.JPEG<
                   ilename>

Comunque, voglio passare <filename>abc.JPEG<^Lilename>a<filename>abc.JPEG</filename>

Ho già trovato un comando per cambiare una parola in molti file, come ad esempio

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

Ma quel comando non funziona nel mio caso, perché non è in grado di riconoscere la parola di ricerca quando scrivo ^L.

Come posso passare <filename>abc.JPEG<^Lilename>a <filename>abc.JPEG</filename>in molti file?


6
Apparentemente qualcuno lo usava <\filename>invece che </filename>in un contesto in cui \fsarebbe stato interpretato come il carattere del feed del modulo. Probabilmente dovresti rintracciare l'origine di questi file e sottolineare il problema con il loro strumento di generazione allo sviluppatore. Per correggere i file, la risposta accettata va bene.
Hans-Martin Mosner,

Risposte:


17

Control-L (rappresentato come ^L) è il carattere "avanzamento modulo". In ASCII, ha un valore decimale 12 ( Lè la dodicesima lettera dell'alfabeto) o un valore esadecimale 0c:

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

$ printf 'foo\x0cbar\n'
foo
   bar

Puoi sostituirlo usando strumenti come sed specificando il codice di escape esadecimale:

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

In alternativa, componi ^Ldirettamente usando la sequenza della tastiera CTRL+ V CTRL+L

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

Per il tuo sostituto specifico, dato

$ printf '<\x0cilename\n'
<
 ilename

poi

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

(il gmodificatore viene aggiunto nel caso in cui vi sia più di un'istanza per riga).


Nel mio caso, "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" non funziona. Ma, secondo la tua risposta, "$ find. -Exec perl -pi -e 's / <\ x0cilename> / <\ / nomefile> / g' {} \;" funziona bene. Grazie per la risposta :)
Yang

@Yang mi dispiace, mi sono appena reso conto di aver confuso barra rovesciata e barra rovesciata nella mia risposta (corretta ora) - ancora non sono sicuro del motivo per cui ciò avrebbe impedito il funzionamento della versione sed
steeldriver

Un'ottima risposta! Sarebbe ancora meglio se includesse dire findche si sovrapponeva a quei 50000 file XML e li elaborava automaticamente (e faceva anche un backup).
Kingsley,

2

Come sottolinea Hans-Martin Mosner nei commenti, sembra che qualcuno abbia usato barre rovesciate invece di barre rovesciate durante la generazione dell'XML (o forse ha eseguito l'intera <filename>sezione attraverso un convertitore Unix-Windows che era troppo zelante sulle barre). \fè una sequenza di escape utilizzata raramente per un carattere di avanzamento modulo, noto anche come U + 0C o ^ L. Quindi alcuni passaggi successivi della pipeline hanno poi sostituito i caratteri \fletterali U + 0C.

Fortunatamente, U + 0C è un personaggio estremamente raro che difficilmente può essere trovato intenzionalmente in qualsiasi tipo di XML. E dal momento che solo \fprodurrebbe questo, al contrario di (diciamo) \go \k, un'operazione di ricerca e sostituzione universale dovrebbe risolvere non solo </filename>, ma anche </folder>, </file>o qualsiasi altra cosa che ha ottenuto maciullato.

Questo è ciò che fa la sceneggiatura di Steeldriver; Lo renderei solo leggermente più generale:

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

Questo significa "(s) wap tutte le istanze di \x0c(ovvero, U + 0C) a /f, (g) lobalmente".


2

\fè il carattere di feed del modulo in Perl. Sembra che questi file non validi siano stati creati da qualcuno nuovo sia in Perl che in XML.

Ecco una correzione molto Perlier - che soddisfa anche gli obiettivi dell'OP di automatizzare l'aggiornamento di tutti i file, a differenza della risposta accettata con sed, che funzionerà su un solo file alla volta in quanto non associato find.

\fpuò semplicemente essere impiegato da solo invece del codice esadecimale x0c.

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

Qui ho aggiunto -type fa tel findper restituire solo file semplici, altrimenti findtornerà .nell'elenco e genererà un avviso quando si tenta di modificarlo, sebbene tutto il resto continuerà a funzionare.

Ho anche reso il regex più facile da vedere usando la xbandiera che ignora gli spazi reali, permettendoti di distanziare gli elementi del tuo regex. Se non ti piace questo, eccolo senza:

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

E nel caso probabile che tutti i caratteri del feed del modulo siano spuri e che tutti debbano essere sostituiti da /f, è possibile ridurre ulteriormente il limite di una riga:

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

Non è necessario utilizzare le barre in avanti per circondare gli elementi del comando di sostituzione regex ( s///) in Perl. Puoi usare qualsiasi simbolo. Se si sceglie di utilizzare qualsiasi tipo di simbolo simile a parentesi quadre, tuttavia, è necessario utilizzare entrambi: s[old][new]ad esempio.

Dal momento che non sto usando le barre, non devo sfuggire a nessuna barra.

Per quanto riguarda -i.bkp: perl -pi -econsente di modificare sul posto - ma se si desidera un'assicurazione aggiuntiva nel caso in cui il programma Perl di ricerca e sostituzione sia errato, è possibile inserire un'estensione di file in modo che crei una copia dei file originali per voi. Ecco, l'ho usato .bkp.

Nelle versioni più recenti di Perl, la modifica sul posto è stata aggiornata per essere più resiliente nel caso in cui il sistema subisca un problema grave come la perdita di energia o anche lo spazio su disco. Ecco l'autore del Perl brian d foy sul miglioramento delle modifiche sul posto negli ultimi Perls.

Dovresti considerare l'utilizzo di Perl per questo tipo di attività, perché è un linguaggio di programmazione per scopi generici estremamente potente ma sottovalutato, uno dei cui obiettivi progettuali originali era quello di sostituire sede awkcon qualcosa di molto meglio.

Le capacità di corrispondenza regex di Perl 5 e la sintassi regex migliorata superano di gran lunga quelle di sed, awke in effetti tutti gli altri linguaggi di programmazione oltre a Perl 6, rendendo Perl la scelta più sensata per manipolazioni regex sia semplici che avanzate.

Per chiarire: sedfunzionerà bene findanche con e puoi anche usare sed -i.bkpper fare un backup di ogni file modificato, ma per quanto ne so non presenta la resilienza extra in Perl 5.28 e versioni successive. Utilizza anche la sintassi di regex UNIX ® tradizionale più clunkier e molto meno potente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.