Как я могу изменить код ^ L во многих файлах в Ubuntu?

8

У меня много XML-файлов, более 50000 из них.

В некоторых файлах XML некоторые файлы пишутся так

<filename>abc.JPEG<^Lilename>

^Lэто всего лишь один символ, но я не могу найти, что ^Lзначит с Google.

Когда я использую, catчтобы напечатать содержимое файла, он показывает, как показано ниже

<filename>abc.JPEG<
                   ilename>

Во всяком случае, я хочу изменить <filename>abc.JPEG<^Lilename>на<filename>abc.JPEG</filename>

Я уже нашел какую-то команду, чтобы изменить слово во многих файлах, таких как

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

Но эта команда не работает в моем случае, потому что она не может распознать искомое слово, когда я просто набираю ^L.

Как я могу изменить , <filename>abc.JPEG<^Lilename>чтобы <filename>abc.JPEG</filename>во многих файлах?

Ян
источник
6
Видимо, кто-то использовал <\filename>вместо того, чтобы </filename>в контексте, где \fбудет интерпретироваться как символ подачи формы. Вам, вероятно, следует отследить источник этих файлов и указать разработчику на проблему с их инструментом генерации. Для исправления файлов, принятый ответ просто отлично.
Ханс-Мартин Моснер

Ответы:

17

Control-L (обозначается как ^L) - это символ «подача формы». В ASCII он имеет десятичное значение 12 ( Lявляется 12-й буквой алфавита) или шестнадцатеричное значение 0c:

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

$ printf 'foo\x0cbar\n'
foo
   bar

Вы можете заменить его с помощью таких инструментов, как sed, указав шестнадцатеричный escape-код:

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

В качестве альтернативы, создавать ^Lнепосредственно с помощью клавиатуры последовательности CTRL+ V CTRL+L

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

Для вашей конкретной замены, учитывая

$ printf '<\x0cilename\n'
<
 ilename

тогда

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

( gмодификатор добавляется, если в строке более одного экземпляра).

steeldriver
источник
В моем случае "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" не работает. Но, согласно вашему ответу, "$ find. -Exec perl -pi -e 's / <\ x0cilename> / <\ / filename> / g' {} \;" работает хорошо. Спасибо за ваш ответ :)
Ян
@Yang извините, я только что понял, что перепутал косую черту и обратную косую черту в своем ответе (исправлено сейчас) - все еще не уверен, почему это помешало бы работать версии sed
steeldriver
Очень хороший ответ! Было бы еще лучше, если бы он включал, например, a, findкоторый зацикливался на этих 50000 XML-файлах и автоматически обрабатывал каждый из них (и тоже делал резервную копию).
Кингсли
2

Как отмечает Ханс-Мартин Моснер в комментариях, кажется, что кто-то использовал обратную косую черту вместо прямой косой черты при генерации XML (или, возможно, управлял всем <filename>разделом через конвертер Unix-в-Windows, который был слишком усердным в отношении косых черт ). \fявляется редко используемой escape-последовательностью для символа подачи формы, он же U + 0C или ^ L. Таким образом, на более позднем этапе конвейера заменили \fбуквенные символы U + 0C.

К счастью, U + 0C - чрезвычайно редкий символ, который вряд ли можно найти намеренно в любом виде XML. И так как только \fбудет производить это, в отличии от (например) \gили \k, универсальной находки и замены должны исправить не только , </filename>но и </folder>, </file>или что - нибудь еще , что получило искажаются.

Это то, что делает sed-скрипт Steeldriver; Я бы просто сделал это немного более общим:

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

Это означает, что «все действия \x0c(т. /fЕ. U + 0C) должны (g) лоббировать».

Draconis
источник
2

\fявляется символом подачи формы в Perl. Похоже, что эти искаженные файлы были созданы кем-то новым для Perl и XML.

Вот большое исправление Perlier, которое также отвечает задачам OP по автоматизации обновления всех файлов, в отличие от принятого ответа с помощью sed, который будет работать только с одним файлом за раз, поскольку он не связан с парой find.

\fможно просто использовать самому вместо шестнадцатеричного кода x0c.

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

Здесь я добавил -type fв tel findтолько возврат простых файлов - в противном случае findон вернется .в список и вызовет предупреждение при попытке его редактирования, хотя все остальное будет работать.

Я также сделал регулярное выражение более легким для просмотра, используя xфлаг, который игнорирует реальные пробелы, позволяя вам выделить элементы вашего регулярного выражения. Если вам не нравится это, вот это без:

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

И в вероятном случае, когда все символы подачи формы являются ложными, и все они должны быть заменены /f, то вы можете еще больше уменьшить размер строки:

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

Вам не нужно использовать косую черту, чтобы окружить элементы команды подстановки регулярных выражений ( s///) в Perl. Вы можете использовать любой символ. Однако, если вы решите использовать любой вид парного символа в скобках, вам придется использовать оба из них: s[old][new]например.

Поскольку я не использую косые черты, мне не нужно избегать косых черт.

Что касается -i.bkp: perl -pi -eпозволяет редактировать на месте - но если вам нужна дополнительная страховка на случай, если вы неправильно установили Perl-программу поиска, вы можете добавить расширение файла, чтобы оно сделало копию исходных файлов для вы. Здесь я использовал .bkp.

В самых последних версиях Perl редактирование на месте было обновлено, чтобы сделать его более устойчивым на случай, если ваша система также столкнется с серьезной проблемой, такой как потеря питания или нехватка дискового пространства. Вот автор Perl Брайан Д. Фой о улучшенном редактировании на месте в последних версиях Perls.

Вы должны рассмотреть возможность использования Perl для этих видов задач, потому что это чрезвычайно мощные , но недооцененным языком программирования общего назначения, один из которых оригинального дизайна цель был заменить sedи awkс чем - то гораздо лучше.

Возможности сопоставления регулярных выражений в Perl 5 и улучшенный синтаксис регулярных выражений намного превосходят возможности sed, awkи даже любой другой язык программирования, кроме Perl 6, что делает Perl наиболее разумным выбором как для простых, так и для расширенных манипуляций с регулярными выражениями.

Чтобы уточнить: sedс ним findтоже будет хорошо, и вы также можете использовать его sed -i.bkpдля создания резервной копии каждого отредактированного файла, но, насколько я знаю, он не имеет дополнительной устойчивости в Perl 5.28 и выше. Он также использует более грубый и гораздо менее мощный традиционный синтаксис регулярных выражений UNIX ®.

Медлок Перлман
источник