2016-02-20 3 views
0

У меня есть большой XML-файл размером около 2 ГБ. Чтобы все было интересно, все данные находятся в одной строке.Поиск и замена в большом файле с одной строкой (~ 2 ГБ) в Linux

Я пытаюсь вставить символ новой строки в конце определенных тегов в этом файле, чтобы сделать его многострочным файлом, который позволит мне разбить его и сделать с ним больше.

[email protected]:~# sed -i -e 's/\<\/Dummy\>/\<\/Dummy\>\\\n/g' file_name 

Я пробовал sed, vi и joe без везения. Длина каждого узла в XML различна, поэтому я не могу разбить файл на основе количества символов.

Есть ли способ сделать этот большой одиночный файл в многострочном файле через командную строку?

ответ

0

Я думаю, что на самом деле я бы это сделал с gawk, а не с sed.

Вы не указали входные данные, поэтому я сделаю некоторые из них.

$ printf '<a><b></b><b></b></a><a><c></c></a>' | gawk -vRS='</a>' '{print $0 RS}' 
<a><b></b><b></b></a> 
<a><c></c></a> 

Как правило, AWK (или простак) рассмотрит каждую строку быть уникальной записью, с каждой линией разделяется на поля, разделенных пробелами.

Если вы разделили записи каким-либо XML-тегом, вы можете положиться на то, что после печати каждой «входной записи» print добавит новую строку как разделитель выходной записи по умолчанию.

В отличие от решения sed, которое попытается прочитать одну целую «запись» (строку) в память для выполнения действий над ней, я подозреваю, что это решение будет проходить через ваш файл, только используя достаточное количество памяти для «запоминания» пространство между разделителями записей. (Это относится к проблеме «большого файла».)

Три других примечания.

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

Во-вторых, поскольку в моем примере я определил разделитель записей, который является закрытием тега XML, входные данные могут быть, хотя и иметь ТРИ ЗАПИСИ, третий из которых является нулевым. Если у вас есть новая строка после окончательного «разделителя записей», эта третья запись может быть завершена еще одним RS в вашем выводе. Имейте в виду. Это результат вещи №1.

В-третьих, это простак решение, не AWK решение, потому что другие реализации, как правило, не поддерживают несколько символов в качестве разделителей записей.

YMMV. Это не отличное решение, но этого может быть достаточно для ваших нужд.

+0

Спасибо @ghoti, это решение было самым быстрым, что делало то, что я хотел. – bhowmik

1

Что вы можете сделать, это форматировать это в каноническом xml с xmllint xmllint --format pathtofile.xml, а затем передать его в sed.

+0

Или 'xmlformat' (например,' brew install xmlformat' на OS X). – peak

+0

Я попытался сделать это, но xmllint запускает некоторое время и не работает с «Killed» в командной строке – bhowmik

0

Я нагло красть мой вход от ghoti «s answer:

$ cat file_name 
<a><b></b><b></b></a><a><c></c></a> 

Есть несколько вещей неправильно с вашей попыткой, модифицированных на более короткий тег здесь:

sed -i -e 's/\<\/a\>/\<\/a\>\\\n/g' file_name 
  • Нет необходимости в -e в этом случае:

    sed -i 's/\<\/a\>/\<\/a\>\\\n/g' file_name 
    
  • Чтобы избежать необходимости избежать /, мы можем использовать другой разделитель:

    sed -i -e 's|\</a\>|\</a\>\\\n|g' file_name 
    
  • Если вы убегаете < > с \< \>, СЭД думает, что вы имели в виду «границы слов», но в этом случае, вы имеете в виду буквальный < > и не должны их избежать:

    sed -i -e 's|</a>|</a>\\\n|g' file_name 
    

    Это уже делает что-то :

    $ sed -i -e 's|</a>|</a>\\\n|g' file_name 
    <a><b></b><b></b></a>\ 
    <a><c></c></a>\ 
    [empty line here] 
    

Так что, если вы на самом деле хотели \ в конце каждой строки, мы почти там. (Если нет, то вы можете просто заменить \\\n на \n.)

  • косметики: не нужно выписывать все, что мы воплотили в замене, мы можем просто использовать &:

    sed -i -e 's|</a>|&\\\n|g' file_name 
    
  • И, наконец, если наш файл завершится с <a> (что пример ввода), мы можем удалить обратную косую черту (и новую строку!) С конца нашего вывода:

    $ sed -e 's|</a>|&\\\n|g;s/\\\n$//' file_name 
    <a><b></b><b></b></a>\ 
    <a><c></c></a> 
    

Конечно, все сказанное о манипулировании XML с помощью инструментов, отличных от XML, по-прежнему применяется: вы не должны этого делать, и если вы это сделаете, ожидайте, что ваше решение легко сломается.


По крайней мере GNU СЭД делает, но это помечено «Linux», и я предполагаю, что вы используете GNU СЭД.