Jak mogę zmienić kod ^ L w wielu plikach w Ubuntu?

8

Mam dużo plików XML, ponad 50000 z nich.

W niektórych plikach XML niektóre pliki są zapisywane w ten sposób

<filename>abc.JPEG<^Lilename>

^Lto tylko jedna postać, ale nie mogę znaleźć tego, co ^Lznaczy Google.

Kiedy używam catdo drukowania zawartości pliku, pokazuje to następująco

<filename>abc.JPEG<
                   ilename>

W każdym razie, chcę zmienić <filename>abc.JPEG<^Lilename>na<filename>abc.JPEG</filename>

Znalazłem już polecenie zmiany słowa w wielu plikach, np

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

Ale to polecenie nie działa w moim przypadku, ponieważ nie może rozpoznać szukanego słowa, gdy piszę ^L.

Jak mogę zmienić <filename>abc.JPEG<^Lilename>na <filename>abc.JPEG</filename>wiele plików?

Yang
źródło
6
Najwyraźniej ktoś użył go <\filename>zamiast </filename>w kontekście, który \fbyłby interpretowany jako znak w formularzu. Prawdopodobnie powinieneś wyśledzić źródło tych plików i zwrócić uwagę programisty na problem z ich narzędziem do generowania. W przypadku naprawy plików zaakceptowana odpowiedź jest w porządku.
Hans-Martin Mosner,

Odpowiedzi:

17

Control-L (reprezentowany jako ^L) jest znakiem „form feed”. W ASCII ma wartość dziesiętną 12 ( Ljest 12 literą alfabetu) lub wartość szesnastkową 0c:

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

$ printf 'foo\x0cbar\n'
foo
   bar

Możesz go zastąpić za pomocą narzędzi takich jak sed, określając szesnastkowy kod ucieczki:

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

Możesz też komponować ^Lbezpośrednio, używając sekwencji CTRLklawiszy V CTRL+ +L

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

Podane do konkretnego zamiennika

$ printf '<\x0cilename\n'
<
 ilename

następnie

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

( gmodyfikator jest dodawany w przypadku, gdy występuje więcej niż jedna instancja na linię).

steeldriver
źródło
W moim przypadku „$ printf” <\ x0nazwa_pliku \ n '| sed' s / <\ x0c / <\\ f / g '”nie działa. Ale zgodnie z odpowiedzią: „$ find. -Exec perl -pi -e 's / <\ x0nazwa_pliku> / <\ / filename> / g' {} \;” działa dobrze. Dziękuję za odpowiedź :)
Yang
@ Yang przepraszam, właśnie zdałem sobie sprawę, że pomyliłem ukośnik w przód i w lewo w mojej odpowiedzi (teraz poprawione) - wciąż nie jestem pewien, dlaczego to uniemożliwiłoby działanie wersji sed
steeldriver
Bardzo dobra odpowiedź! Byłoby jeszcze lepiej, gdyby zawierało powiedzmy, findże zapętliło te 50000 plików XML i automatycznie przetworzyło każdy z nich (i również wykonało kopię zapasową).
Kingsley,
2

Jak zauważa Hans-Martin Mosner w komentarzach, wydaje się, że ktoś używał ukośników odwrotnych zamiast ukośników do przodu podczas generowania XML (lub ewentualnie prowadził całą <filename>sekcję przez konwerter Unix-na-Windows, który był nadgorliwy o ukośnikach). \fjest rzadko używaną sekwencją zmiany znaczenia dla znaku w formularzu, znanym również jako U + 0C lub ^ L. Więc jakiś późniejszy etap potoku zastąpił \fliteralnymi znakami U + 0C.

Na szczęście U + 0C jest niezwykle rzadką postacią, która prawdopodobnie nie zostanie celowo znaleziona w jakimkolwiek formacie XML. A skoro tylko \fbędzie produkować ten, w przeciwieństwie do (powiedzmy) \glub \k, uniwersalny find-a-wymienić należy ustalić nie tylko </filename>, ale również </folder>, </file>albo cokolwiek innego, ale zniekształcone.

Tak właśnie działa skrypt sed steriderrivera; Chciałbym tylko uczynić to nieco bardziej ogólnym:

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

Oznacza to „(s) wap we wszystkich przypadkach \x0c(to znaczy U + 0C) do /f, (g) lobalnie”.

Draconis
źródło
2

\fto znak kanału informacyjnego w Perlu. Wygląda na to, że te zniekształcone pliki zostały utworzone przez kogoś nowego zarówno w Perlu, jak i XML.

Oto poprawka o wiele bardziej precyzyjna - która również spełnia cele PO dotyczące zautomatyzowania aktualizacji wszystkich plików, w przeciwieństwie do akceptowanej odpowiedzi z sed, która będzie działać tylko na jednym pliku na raz, ponieważ nie jest sparowany find.

\fmożna po prostu zastosować sam zamiast kodu szesnastkowego x0c.

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

Tutaj dodałem -type fdo tel, aby zwracał findtylko zwykłe pliki - w przeciwnym razie findpowróci .na listę i wyśle ostrzeżenie, gdy spróbujesz go edytować, chociaż wszystko inne nadal będzie działać.

Uczyniłem też wyrażenie regularne łatwiejszym, używając xflagi, która ignoruje prawdziwe białe znaki, pozwalając na rozmieszczenie elementów wyrażenia regularnego. Jeśli ci się nie podoba, tutaj jest bez:

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

I w prawdopodobnym przypadku, gdy wszystkie znaki wysuwu formularza są fałszywe i wszystkie powinny zostać zastąpione /f, możesz jeszcze bardziej odchylić linijkę:

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

Nie musisz używać ukośników, aby otoczyć elementy polecenia podstawienia wyrażenia regularnego ( s///) w Perlu. Możesz użyć dowolnego symbolu. Jeśli jednak zdecydujesz się na użycie dowolnego sparowanego symbolu przypominającego nawias klamrowy, musisz użyć ich obu: s[old][new]na przykład.

Ponieważ nie używam ukośników, nie muszę uciekać żadnym ukośnikom.

Jeśli chodzi o -i.bkp: perl -pi -epozwala edytować w miejscu - ale jeśli potrzebujesz dodatkowego ubezpieczenia na wypadek, gdyby Twój program Perl znalazł i zamienił źle, możesz umieścić rozszerzenie pliku, aby utworzyło kopię oryginalnych plików dla ty. Tutaj wykorzystałem .bkp.

W najnowszych wersjach Perla edycja lokalna została zaktualizowana, aby była bardziej odporna na wypadek poważnych problemów z systemem, takich jak utrata zasilania lub brak miejsca na dysku. Oto autor Perla, brian d foy, na temat ulepszonej edycji na miejscu w najnowszym Perlu.

Należy wziąć pod uwagę przy użyciu Perl dla tego rodzaju zadań, ponieważ jest to bardzo potężne, ale pod oceniane językiem programowania ogólnego przeznaczenia, którego jednym z celów było oryginalne wzornictwo zastąpić sedi awkcoś znacznie lepiej.

Regex możliwości dopasowywania Perl 5'S i ulepszona składni regex znacznie przekraczają te sed, awki rzeczywiście każdy inny język programowania oprócz Perl 6, dzięki czemu Perl najbardziej rozsądny wybór zarówno dla prostych, jak i zaawansowanych manipulacji regex.

Wyjaśnienie: sedbędzie również działało OK findi możesz również użyć sed -i.bkpdo wykonania kopii zapasowej każdego edytowanego pliku, ale o ile wiem, nie ma dodatkowej odporności w Perlu 5.28 i nowszych. Wykorzystuje również bardziej skomplikowaną i znacznie mniej wydajną tradycyjną składnię wyrażeń regularnych UNIX ®.

Medlock Perlman
źródło