строки в столбцы с awk

Я должен следовать примеру вывода:

<HARDWARE> <NAME>WIN1</NAME> <OS>Windows 7</OS> <IP>1.2.3.4</IP> <DOMAIN>contoso.com</DOMAIN> </HARDWARE> <HARDWARE> <NAME>WIN2</NAME> <OS>Windows 8</OS> <IP>10.20.30.40</IP> <DOMAIN>contoso.com</DOMAIN> </HARDWARE> 

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

 WIN1 Windows 7 1.2.3.4 contoso.com WIN2 Windows 8 10.20.30.40 contoso.com 

Ищете решение для использования стандартных инструментов, таких как awk, sed и т. Д.

5 Solutions collect form web for “строки в столбцы с awk”

Пожалуйста, не используйте awk sed и т. Д. Они не могут правильно обрабатывать XML . XML делает кучу вещей, таких как пробелы, переводы строк, унарные теги и т. Д., Что означает, что регулярные выражения не очень надежны – они прерываются беспорядочно, следуя совершенно правильному изменению XML по строке.

Способ обработки XML – это синтаксический анализатор. xmlstarlet обычно используется в Linux. Потому что я еще не видел, чтобы это предлагалось – я бы использовал perl. Например:

 #!/usr/bin/perl use strict; use warnings; use XML::Twig; my $twig = XML::Twig -> parsefile ('your_xml_file.xml'); foreach my $HW ( $twig -> findnodes ( '//HARDWARE' ) ) { print join ( "\t", map { $_ -> text } $HW -> children ),"\n"; } 
  • Разбор XML
  • итерации элементов HARDWARE .
  • Извлечь text из детей
  • принт это.

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

 #!/usr/bin/perl use strict; use warnings; use XML::Twig; my @fields_to_show = qw ( OS NAME ); my $twig = XML::Twig -> parsefile ( 'your_filename.xml' ); foreach my $HW ( $twig -> findnodes ( '//HARDWARE' ) ) { my %fields = map { $_ -> tag => $_ -> text } $HW -> children; print join ("\t", @fields{@fields_to_show}),"\n"; } 

Он генерирует хэш (ассоциативный массив), называемый %fields которые выглядят как (для каждого элемента):

 $VAR1 = { 'OS' => 'Windows 7', 'NAME' => 'WIN1', 'DOMAIN' => 'contoso.com', 'IP' => '1.2.3.4' }; 

И затем мы используем @fields_to_show чтобы указать, что отображать и в каком порядке.

Таким образом, это будет печатать:

 Windows 7 WIN1 Windows 8 WIN2 

NB: Я также должен «исправить» ваш XML, потому что без одного корневого тега это неверно. Другие ответы упомянули об этом. Спецификация XML довольно строгая – сломанный XML должен быть отклонен. Таким образом, на самом деле довольно плохая форма для «исправления» XML, и обычно я предлагаю ударить того, кто сгенерировал ее вокруг головы, с копией спецификации XML.

data.xml свой XML- data.xml , оберните весь свой XML в родительский <DATA> 1 или другой, который вы data.xml , файл с именем data.xml :

 <DATA> <HARDWARE> <NAME>WIN1</NAME> <OS>Windows 7</OS> <IP>1.2.3.4</IP> <DOMAIN>contoso.com</DOMAIN> </HARDWARE> <HARDWARE> <NAME>WIN2</NAME> <OS>Windows 8</OS> <IP>10.20.30.40</IP> <DOMAIN>contoso.com</DOMAIN> </HARDWARE> </DATA> 

Использование xmlstarlet +

  xmlstarlet sel -T -t -m /DATA/HARDWARE -v "concat(NAME,' ',OS,' ',IP,' ',DOMAIN)" -n data.xml | column -t 

дает:

 WIN1 Windows 7 1.2.3.4 contoso.com WIN2 Windows 8 10.20.30.40 contoso.com 

Редактировать:

Основываясь на замечательном замечании Peter.O в комментариях и его ответе ниже , давайте отправим вывод с разделителями column -ts$'|' на column -ts$'|' , поэтому что-то вроде:

 xmlstarlet sel --indent-tab -T -t -m /DATA/HARDWARE -v "concat(NAME,'|',OS,'|',IP,'|',DOMAIN)" -n data.xml | column -ts$'|' 

Теперь поля прекрасно выравниваются, даже если у них есть пробелы:

 WIN1 Windows 7 1.2.3.4 release 5 contoso.com Really long OS X Windows 8 10.20.30.40 contoso.com 

1. Или используйте { echo '<DATA>'; cat file_name; echo '</DATA>'; } | xmlstarlet ... { echo '<DATA>'; cat file_name; echo '</DATA>'; } | xmlstarlet ... { echo '<DATA>'; cat file_name; echo '</DATA>'; } | xmlstarlet ... как отмечает Peter.O в комментарии ниже

2. Использование пространства в качестве разделителя не выравнивает столбцы должным образом

С вашим примером и GNU sed:

 sed -n 's/<[^>]*>//g;s/^ *//g;/./p' file | paste -d ";" - - - - | column -t -s ";" 

Вывод:

 WIN1 Windows 7 1.2.3.4 contoso.com
 WIN2 Windows 8 10.20.30.40 contoso.com

Я предполагаю, что ваш файл не содержит ; , Если вам нужен CSV remove | column -t -s ";" | column -t -s ";" ,

Следующий скрипт awk (плюс column для вывода табуляции) будет передавать любую последовательность размещения суб- тэгов и любое разделение пробелов между тегами – т.е. он будет обрабатывать формат ввода выборки OP, а также следующий образец, который не имеет пробелов и по- разному упорядоченных подтег:

  <HARDWARE><OS>Windows 7</OS><IP>1.2.3.4</IP><DOMAIN>contoso.com</DOMAIN><NAME>WIN1</NAME></HARDWARE><HARDWARE><NAME>WIN2</NAME><OS>Windows 8</OS><DOMAIN>contoso.com</DOMAIN><IP>10.20.30.40</IP></HARDWARE> 

 awk 'BEGIN{ RS="[[:space:]]*</?HARDWARE>[[:space:]]*" FS="[[:space:]]*<|</[^<>/]+>[[:space:]]*" tn=split( "NAME OS IP DOMAIN", tag_order, " " ) } $0 { delete tag for( i=1;i<=NF;i++ ) if($i) { n=index($i,">"); tag[substr($i,1,n-1)]=substr($i,n+1) } for( i=1;i<=tn;i++ ) printf "%s\t", tag[tag_order[i]]; print "" }' file | column -ts$'\t' 

вывод:

 WIN1 Windows 7 1.2.3.4 contoso.com WIN2 Windows 8 10.20.30.40 contoso.com 

с awk – произвольно задавать каждый столбец длиной 15 символов, выравнивать по левому краю и заполнять пробелами:

 awk ' BEGIN { FS = "<[A-Za-z/]+>" } { if ( NR % 6 == 0 ) { printf"\n" } else if ( $2 != "" ) { printf"%-15s", $2 } }' file 

Или как в других ответах в сочетании со column

 awk ' BEGIN { FS = "<[A-Za-z/]+>" } { if ( NR % 6 == 0 ) { printf"\n" } else if ( $2 != "" ) { printf"%s ", $2 } }' file | column -t 
  • Список имен файлов, содержащих строку, которая встречается между двумя другими строками
  • regex заменить текст в XML-файле в узле из командной строки
  • Найти соответствующие MD5 и XML в каталоге
  • Преобразование файла субтитров xml в формат srt
  • XML-документ Microsoft Word
  • конвертировать CDA XML в PDF без * TeX?
  • Как удалить строку из тега в сценарии оболочки?
  • Разделить XML-файл на несколько файлов
  • Как я могу добавить # перед каждой строкой блока текста?
  • Сценарий оболочки или команда для вырезания текста и двоичных файлов выдержки из больших файлов журнала
  • Как получить определенную строку в xml с помощью python или perl и т. Д.
  • Как проверить корректность XML-файла 4 ГБ?
  • Interesting Posts

    Вычисление стандартного отклонения с известным средним значением

    rsync mkstemp failed Неверный аргумент (22) с поддержкой davfs облака Box.com

    Настройки gedit выделены серым цветом

    Как может плохой старый пользователь, не являющийся пользователем root, получить систему отвалов ядра?

    Переименование файлов без расширения файлов

    / usr / bin / ls: / usr / bin / ls: невозможно выполнить двоичный файл

    PCI-e SSD – не отображается в iostat или sar sysstat

    Почему bash даже анализирует / запускает материал, помещенный в переменную окружения?

    Как отправить электронное письмо самому себе на том же локальном компьютере (порт tcp 25)

    mptscsih: ioc0: task abort: SUCCESS (rv = 2002) вызывает 30 секунд замораживания

    Как печатать самую длинную строку в файле?

    Имя указанной сети SAMBA больше не доступно

    Как записывать более одного каталога?

    Какие источники добавить, чтобы установить cuda toolkit с apt на Debian?

    Показать ветви git, которые отклоняются от пульта?

    Linux и Unix - лучшая ОС в мире.