Серийный раздел SED для разных файлов

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

some text ..... HEAD context A TAIL some text ..... HEAD context B TAIL .... some text .... HEAD context C TAIL .... some text

Мне нужно вырезать секцию с помощью context A и перейти к контексту файлаA, затем context B в файл contextB и т. д. (Все файлы должны содержать синтаксис HEAD context x TAIL). Проблема в том, что все контексты начинаются и заканчиваются в одном и том же регулярном выражении (HEAD и TAIL).

Можете ли вы мне помочь?

Это небольшое обновление, потому что, может быть, я недостаточно прояснил его: пусть скажет мой файл выглядит так:

some text 1 <config> 1 2 3 </config> some text 2 <config> 4 5 6 </config> some text 3 <config> 7 8 9 </config> some text 4

, и я хочу, чтобы файл с именем:

«первым», который содержит:

<config> 1 2 3 </config>

«second», которые содержат: [ ! d6] <config> 4 5 6 </config>

и т. д.

1
задан 17 January 2018 в 15:49

12 ответов

Это проще сделать с awk:

awk -v RS="HEAD\n" -v FS="\n" 'NR>1{print "HEAD\n" $0 > $1".txt"}' ex

Примечания: регистры

RS="HEAD\n" разделены «HEAD \ n» FS="\n", каждое поле является line NR>1{print "HEAD\n" $0 > $1} для всех регистров, кроме первого, напишите его в файл с именем field 1 - «$ 1»

UPDATE: для нового вопроса:

awk -v RS="<config>\n" -F"</config>" 'NR>1{print RS $1 FS > "conf-"NR-1}' ex

Конфигурация выходы хранятся в файлах с именем «conf-1»

1
ответ дан 22 May 2018 в 15:29

Это проще сделать с awk:

awk -v RS="HEAD\n" -v FS="\n" 'NR>1{print "HEAD\n" $0 > $1".txt"}' ex

Примечания: регистры

RS="HEAD\n" разделены «HEAD \ n» FS="\n", каждое поле является line NR>1{print "HEAD\n" $0 > $1} для всех регистров, кроме первого, напишите его в файл с именем field 1 - «$ 1»

UPDATE: для нового вопроса:

awk -v RS="<config>\n" -F"</config>" 'NR>1{print RS $1 FS > "conf-"NR-1}' ex

Конфигурация выходы хранятся в файлах с именем «conf-1»

1
ответ дан 17 July 2018 в 22:50

Это проще сделать с awk:

awk -v RS="HEAD\n" -v FS="\n" 'NR>1{print "HEAD\n" $0 > $1".txt"}' ex

Примечания: регистры

RS="HEAD\n" разделены «HEAD \ n» FS="\n", каждое поле является line NR>1{print "HEAD\n" $0 > $1} для всех регистров, кроме первого, напишите его в файл с именем field 1 - «$ 1»

UPDATE: для нового вопроса:

awk -v RS="<config>\n" -F"</config>" 'NR>1{print RS $1 FS > "conf-"NR-1}' ex

Конфигурация выходы хранятся в файлах с именем «conf-1»

1
ответ дан 24 July 2018 в 13:27

Мой скрипт с использованием awk:

#!/bin/bash
for i in $(seq -w $(<"$1" grep -cx "$2")); do
  <"$1" >$i awk -va=$i -vb="$2" -vc="$3" '$0~b{d++;e=1}d==a&&e==1;$0~c{e=0}'
done

Сохраните его, например. myscript.sh, сделайте его выполнимым, перейдите к своему onebig.xml и вызовите его следующим образом:

/path/to/myscript.sh onebig.xml HEAD TAIL

Он вырезает каждую секцию из onebig.xml, начиная с HEAD и заканчивая на TAIL и сохраните их как 1, 2, ... если в разделе 01, 02, ... есть 10 секций, ... если есть 10 - 99 разделов, то как 001, 002, ... если есть от 100 до 999 секций и т. д.

Короткие объяснения

<"$1" grep -cx "$2" - подсчеты вхождения HEAD в onebig.xml, скажем, что это 3 for i in $(seq -w 3); do …; done - петля над каждым вступлением от 1 до 3, опция seq -w добавляет конечные нули, если необходимо <"$1" >$i - читать из onebig.xml и записывать в файл с именем, как текущий счет awk -va=$i -vb="$2" -vc="$3" - start awk и назначьте три переменные, a будет считаться, b будет HEAD и c равным TAIL $0~b{d++;e=1} - если текущая строка содержит содержимое b (= HEAD ]) увеличьте d на единицу и установите e=1 d==a&&e==1 - если d равно a (= текущий счетчик), а e равно 1, тогда распечатайте текущую строку (print подразумеваемые действия; по существу это: если после a -го появления HEAD, и мы находимся между HEAD и TAIL, тогда напечатайте) $0~c{e=0} - если текущая строка содержит содержимое c (= TAIL ]) установить e=0
1
ответ дан 22 May 2018 в 15:29
  • 1
    К сожалению: ./sec.txt: строка 2: синтаксическая ошибка около неожиданного токена $'do\r'' '/sec.txt: line 2: для i в $ (seq -w $ (& lt; "$ 1" grep -cx "$ 2")); делать – TomM 17 January 2018 в 12:17
  • 2
    seq, grep и awk установлены. в моем xml-файле HEAD - & lt; begin & gt; и TAIL составляет & begin & gt ;. Мой сценарий bash называется sec.txt – TomM 17 January 2018 в 12:42
  • 3
    Я вызвал: ./sec.txt q.xml '<config>' '</config>', потому что я хочу искать это регулярное выражение. sec.txt - это скрипт, q.xml - это xml-файл и два параметра – TomM 17 January 2018 в 16:12
  • 4
    Я скопировал его еще раз в новый файл, и он работает, только если я изменю <config>...</config> на start.... end (только для тестирования в XML-файле). Он выглядит как " " " " " " " " " / " символы не распознаются – TomM 17 January 2018 в 18:34
  • 5
    @TomM $'\r' указывает, что вы сохранили файл в конце строки в стиле Windows. Сохраните его снова в стиле Unix. – wjandrea 17 January 2018 в 21:56

Если вы действительно не можете использовать для этого правильный XML-анализатор, я бы предложил awk, например

awk '/^HEAD/ {p=1; ++n} p {print > "context"n} /^TAIL/ {p=0}' file.xml

выведет секции HEAD ... TAIL в числовые имена файлов context1, context2 и т. д.

Для упрощения сортировки вы можете немного улучшить его, построив числовой префикс фиксированной ширины, например

$ awk '/^HEAD/ {p=1; outfile = sprintf("context%03d", ++n)} p {print > outfile} /^TAIL/ {p=0}' file.xml

$ head context*
==> context001 <==
HEAD
context A
TAIL

==> context002 <==
HEAD
context B
TAIL

==> context003 <==
HEAD
context C
TAIL
1
ответ дан 22 May 2018 в 15:29

Пожалуйста, проверьте, помогает ли ниже скрипт:

#!/bin/bash
for x in {A..Z}; do
    # check if the pattern exists in the file
    if grep -qF "context $x" file.txt; then
        # Store the lines between the 2 patterns including the matching lines in a text file
        awk '/context '$x'/,/TAIL/' file.txt > context$x.txt
    else
       echo "Sorry this pattern does not exists in file"
    fi
done
0
ответ дан 22 May 2018 в 15:29
  • 1
    К сожалению, нет. контекст x " например. Контекст A и B различны, поэтому я не могу искать контекст. Я хочу найти первый начальный и конечный раздел (HEAD и TAIL), переместив этот раздел в некоторый файл, после чего я хочу найти второй раздел, перейдите в другой файл и так далее – TomM 17 January 2018 в 12:13

Мой скрипт с использованием awk:

#!/bin/bash for i in $(seq -w $(<"$1" grep -cx "$2")); do <"$1" >$i awk -va=$i -vb="$2" -vc="$3" '$0~b{d++;e=1}d==a&&e==1;$0~c{e=0}' done

Сохраните его, например. myscript.sh, сделайте его выполнимым, перейдите к своему onebig.xml и вызовите его следующим образом:

/path/to/myscript.sh onebig.xml HEAD TAIL

Он вырезает каждую секцию из onebig.xml, начиная с HEAD и заканчивая на TAIL и сохраните их как 1, 2, ... если в разделе 01, 02, ... есть 10 секций, ... если есть 10 - 99 разделов, то как 001, 002, ... если есть от 100 до 999 секций и т. д.

Короткие объяснения

<"$1" grep -cx "$2" - подсчеты вхождения HEAD в onebig.xml, скажем, что это 3 for i in $(seq -w 3); do …; done - петля над каждым вступлением от 1 до 3, опция seq -w добавляет конечные нули, если необходимо <"$1" >$i - читать из onebig.xml и записывать в файл с именем, как текущий счет awk -va=$i -vb="$2" -vc="$3" - start awk и назначьте три переменные, a будет считаться, b будет HEAD и c равным TAIL $0~b{d++;e=1} - если текущая строка содержит содержимое b (= HEAD ]) увеличьте d на единицу и установите e=1 d==a&&e==1 - если d равно a (= текущий счетчик), а e равно 1, тогда распечатайте текущую строку (print подразумеваемые действия; по существу это: если после a -го появления HEAD, и мы находимся между HEAD и TAIL, тогда напечатайте) $0~c{e=0} - если текущая строка содержит содержимое c (= TAIL ]) установить e=0
1
ответ дан 17 July 2018 в 22:50

Если вы действительно не можете использовать для этого правильный XML-анализатор, я бы предложил awk, например

awk '/^HEAD/ {p=1; ++n} p {print > "context"n} /^TAIL/ {p=0}' file.xml

выведет секции HEAD ... TAIL в числовые имена файлов context1, context2 и т. д.

Для упрощения сортировки вы можете немного улучшить его, построив числовой префикс фиксированной ширины, например

$ awk '/^HEAD/ {p=1; outfile = sprintf("context%03d", ++n)} p {print > outfile} /^TAIL/ {p=0}' file.xml $ head context* ==> context001 <== HEAD context A TAIL ==> context002 <== HEAD context B TAIL ==> context003 <== HEAD context C TAIL
1
ответ дан 17 July 2018 в 22:50

Пожалуйста, проверьте, помогает ли ниже скрипт:

#!/bin/bash for x in {A..Z}; do # check if the pattern exists in the file if grep -qF "context $x" file.txt; then # Store the lines between the 2 patterns including the matching lines in a text file awk '/context '$x'/,/TAIL/' file.txt > context$x.txt else echo "Sorry this pattern does not exists in file" fi done
0
ответ дан 17 July 2018 в 22:50

Мой скрипт с использованием awk:

#!/bin/bash for i in $(seq -w $(<"$1" grep -cx "$2")); do <"$1" >$i awk -va=$i -vb="$2" -vc="$3" '$0~b{d++;e=1}d==a&&e==1;$0~c{e=0}' done

Сохраните его, например. myscript.sh, сделайте его выполнимым, перейдите к своему onebig.xml и вызовите его следующим образом:

/path/to/myscript.sh onebig.xml HEAD TAIL

Он вырезает каждую секцию из onebig.xml, начиная с HEAD и заканчивая на TAIL и сохраните их как 1, 2, ... если в разделе 01, 02, ... есть 10 секций, ... если есть 10 - 99 разделов, то как 001, 002, ... если есть от 100 до 999 секций и т. д.

Короткие объяснения

<"$1" grep -cx "$2" - подсчеты вхождения HEAD в onebig.xml, скажем, что это 3 for i in $(seq -w 3); do …; done - петля над каждым вступлением от 1 до 3, опция seq -w добавляет конечные нули, если необходимо <"$1" >$i - читать из onebig.xml и записывать в файл с именем, как текущий счет awk -va=$i -vb="$2" -vc="$3" - start awk и назначьте три переменные, a будет считаться, b будет HEAD и c равным TAIL $0~b{d++;e=1} - если текущая строка содержит содержимое b (= HEAD ]) увеличьте d на единицу и установите e=1 d==a&&e==1 - если d равно a (= текущий счетчик), а e равно 1, тогда распечатайте текущую строку (print подразумеваемые действия; по существу это: если после a -го появления HEAD, и мы находимся между HEAD и TAIL, тогда напечатайте) $0~c{e=0} - если текущая строка содержит содержимое c (= TAIL ]) установить e=0
1
ответ дан 24 July 2018 в 13:27
  • 1
    К сожалению: ./sec.txt: строка 2: синтаксическая ошибка около неожиданного токена $'do\r'' '/sec.txt: line 2: для i в $ (seq -w $ (& lt; "$ 1" grep -cx "$ 2")); делать – TomM 17 January 2018 в 12:17
  • 2
    seq, grep и awk установлены. в моем xml-файле HEAD - & lt; begin & gt; и TAIL составляет & begin & gt ;. Мой сценарий bash называется sec.txt – TomM 17 January 2018 в 12:42
  • 3
    Я вызвал: ./sec.txt q.xml '<config>' '</config>', потому что я хочу искать это регулярное выражение. sec.txt - это скрипт, q.xml - это xml-файл и два параметра – TomM 17 January 2018 в 16:12
  • 4
    Я скопировал его еще раз в новый файл, и он работает, только если я изменю <config>...</config> на start.... end (только для тестирования в XML-файле). Он выглядит как & quot; & quot; & quot; & quot; & quot; & quot; & quot; & quot; & quot; / & quot; символы не распознаются – TomM 17 January 2018 в 18:34
  • 5
    @TomM $'\r' указывает, что вы сохранили файл в конце строки в стиле Windows. Сохраните его снова в стиле Unix. – wjandrea 17 January 2018 в 21:56

Если вы действительно не можете использовать для этого правильный XML-анализатор, я бы предложил awk, например

awk '/^HEAD/ {p=1; ++n} p {print > "context"n} /^TAIL/ {p=0}' file.xml

выведет секции HEAD ... TAIL в числовые имена файлов context1, context2 и т. д.

Для упрощения сортировки вы можете немного улучшить его, построив числовой префикс фиксированной ширины, например

$ awk '/^HEAD/ {p=1; outfile = sprintf("context%03d", ++n)} p {print > outfile} /^TAIL/ {p=0}' file.xml $ head context* ==> context001 <== HEAD context A TAIL ==> context002 <== HEAD context B TAIL ==> context003 <== HEAD context C TAIL
1
ответ дан 24 July 2018 в 13:27

Пожалуйста, проверьте, помогает ли ниже скрипт:

#!/bin/bash for x in {A..Z}; do # check if the pattern exists in the file if grep -qF "context $x" file.txt; then # Store the lines between the 2 patterns including the matching lines in a text file awk '/context '$x'/,/TAIL/' file.txt > context$x.txt else echo "Sorry this pattern does not exists in file" fi done
0
ответ дан 24 July 2018 в 13:27
  • 1
    К сожалению, нет. контекст x & quot; например. Контекст A и B различны, поэтому я не могу искать контекст. Я хочу найти первый начальный и конечный раздел (HEAD и TAIL), переместив этот раздел в некоторый файл, после чего я хочу найти второй раздел, перейдите в другой файл и так далее – TomM 17 January 2018 в 12:13

Другие вопросы по тегам:

Похожие вопросы: