Grep для нескольких шаблонов в файле - PullRequest
0 голосов
/ 06 марта 2012

Я бы хотел посчитать количество узлов xml в моем файле xml (grep или как-то еще).

....
<countryCode>GBR</countryCode>
<countryCode>USA</countryCode>
<countryCode>CAN</countryCode>
...
<countryCode>CAN</countryCode>
<someNode>USA</someNode>
<countryCode>CAN</countryCode>
<someNode>Otherone</someNode>
<countryCode>GBR</countryCode>
...

Как рассчитать количество отдельных стран, таких как CAN = 3, США = 1, GBR = 2? Без указания названий стран может быть еще несколько стран?

Обновление:

Помимо кода страны есть другие узлы

Ответы [ 8 ]

5 голосов
/ 06 марта 2012

Моим простым предложением было бы использовать sort и uniq -c

$ echo '<countryCode>GBR</countryCode>
<countryCode>USA</countryCode>
<countryCode>CAN</countryCode>
<countryCode>CAN</countryCode>
<countryCode>CAN</countryCode>
<countryCode>GBR</countryCode>' | sort | uniq -c
      3 <countryCode>CAN</countryCode>
      2 <countryCode>GBR</countryCode>
      1 <countryCode>USA</countryCode>

, где вы бы указали на выходе вашего grep вместо echo.Более надежное решение - использовать XPath.Если ваш XML-файл выглядит как

<countries>
  <countryCode>GBR</countryCode>
  <countryCode>USA</countryCode>
  <countryCode>CAN</countryCode>
  <countryCode>CAN</countryCode>
  <countryCode>CAN</countryCode>
  <countryCode>GBR</countryCode>
</countries>

, тогда вы могли бы использовать:

$ xpath -q -e '/countries/countryCode/text()'  countries.xml  | sort | uniq -c
      3 CAN
      2 GBR
      1 USA

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

$ xpath -q -e '//countryCode/text()'  countries.xml  | sort | uniq -c
      3 CAN
      2 GBR
      1 USA
2 голосов
/ 06 марта 2012

grep может дать общее количество, но не для каждого шаблона; для этого вы должны использовать uniq -c:

$ uniq -c <(sort file)
  1 
  1  
  3 <countryCode>CAN</countryCode>
  2 <countryCode>GBR</countryCode>
  1 <countryCode>USA</countryCode>

Если вы хотите избавиться от пустых строк и тегов, добавьте sed:

$ sed -e '/^[[:space:]]*$/d' -e 's/<.*>\([A-Z]*\)<.*>/\1/g' test | sort | uniq -c
  3 CAN
  2 GBR
  1 USA

Чтобы удалить строки без кода страны, добавьте еще одну команду к sed:

$ sed -e '/countryCode/!d' -e '/^[[:space:]]*$/d' -e 's/<.*>\([A-Z]*\)<.*>/\1/g' test | sort | uniq -c
  3 CAN
  2 GBR
  1 USA
1 голос
/ 06 марта 2012
sed -n "s/<countryCode>\(.*\)<\/countryCode>/\1/p"|sort|uniq -c
1 голос
/ 06 марта 2012

быстро и грязно (только на основе вашего примера):

awk -F'>|<' '{a[$3]++;}END{for(x in a)print x,a[x]}' file

тест:

kent$  cat t.txt
<countryCode>GBR</countryCode>
<countryCode>USA</countryCode>
<countryCode>CAN</countryCode>
<countryCode>CAN</countryCode>
<countryCode>CAN</countryCode>
<countryCode>GBR</countryCode>

kent$  awk -F'>|<' '{a[$3]++;}END{for(x in a)print x,a[x]}' t.txt 
USA 1
GBR 2
CAN 3
0 голосов
/ 06 марта 2012

Быстро и просто:

grep countryCode ./file.xml |сортировать |uniq -c

0 голосов
/ 06 марта 2012

Если ваш файл настроен так, как вы показали нам, awk может сделать это следующим образом:

awk -F '<\/?countryCode>' '{ a[$2]++} END { for (e in a) { printf("%s\t%i\n",e,a[e]) }' INPUTFILE

Если в строке более одного тега <countryCode>, вы все равно можете настроить какой-либо канал, чтобы сделать его одной строкой, например ::10000

sed 's/<countryCode>/\n<countryCode>/g' INPUTFILE | awk ...

Примечание , если <countryCode> охватывает несколько строк, он не будет работать должным образом.

В любом случае , я бы рекомендовал использовать xpath для такого рода задач (для perl модуля xml::xpath имеется утилита CLI.

0 голосов
/ 06 марта 2012

Примерно так:

grep -e 'regex' file.xml | sort | uniq -c

Конечно, вам нужно предоставить регулярное выражение, соответствующее вашим потребностям.

0 голосов
/ 06 марта 2012
cat dummy | sort |cut -c14-16 | sort |tail -6 |awk  '{col[$1]++} END {for (i in col) print i, col[i]}'

Думмируйте имя вашего файла и замените 6 в -6 на n-2 (n - нет строк в вашем файле данных)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...