Посчитайте частоту каждой пары, которая ссылается на карту, используя shell / bash - PullRequest
0 голосов
/ 31 мая 2018

У меня есть данные, которые выглядят так:

 abc.com  Hello World Ann
 abc.com  Hi there friend
 def.com  Hello Sam
 def.com  Hello Dan
 abc.com  Hello World Mary

Строка B может содержать различный текст, но я извлек ключевые слова из этой строки для сопоставления с массивом ниже (это не точное соответствиеиз строки B)

keywords=( ["Hello World"]="h1" ["Hello"]="h2" ["Hi there"]="h3" )

Я хочу сгенерировать вывод наподобие этого:

A         Key    Count
abc.com   h1    2
abc.com   h3    1
def.com   h2    1

, который содержит количество вхождений комбинаций и массив A и ключевых слов.Я новичок в использовании сценариев оболочки и не могу начать с какой-либо логики.Все идеи высоко ценятся!Спасибо

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Взяв здесь ссылку на хороший ответ Олива и добавив небольшую логику, в которой выходные данные должны идти в той же последовательности, что и последовательность Input_file.

awk -F' *[AB]: *' '
!b[$2","$3]++{
  c[++count]=$2","$3}
{
  a[$2","$3]++;
  next
}
END{
  print "A","B","Count";
  for(i=1;i<=count;i++){
    print c[i],a[c[i]]}
}' OFS=, Input_file | column -t -s','
0 голосов
/ 31 мая 2018

bash

Поскольку ассоциативные массивы по своей природе неупорядочены, если вам нужно выполнить сравнения в определенном порядке (например, «Hello World» должен совпадать до «B: Hello»), тогда вам нужен другой массив для храненияпорядок ключей.

#!/bin/bash
declare -A keywords=( ["Hello World"]="h1" ["B:Hello"]="h2" ["Hi there"]="h3" )
ordered_keys=( "Hello World" "B:Hello" "Hi there" )
declare -A count

# assume a space between "A:" and "abc.com"
while read -r labelA a b; do
    for key in "${ordered_keys[@]}"; do
        if [[ $b == *"$key"* ]]; then
            let count["$a ${keywords[$key]}"]++
            break
        fi
    done
done <<DATA
A: abc.com B:Hello World Ann
A: abc.com B:Hi there friend
A: def.com B:Hello Sam
A: def.com B:Hello Dan
A: abc.com B:Hello World Mary
DATA

{
    echo "A Key Count"
    for key in "${!count[@]}"; do
        echo $key ${count[$key]}
    done
} | column -t

выходы

A        Key  Count
abc.com  h3   1
abc.com  h1   2
def.com  h2   2

Будьте осторожны, чтобы не делать этого:

produce_the_data | while read ...; do count[x]=y; ...; done

Потому что это будет работать в то время как времяцикл в подоболочке, и после окончания цикла массив count не будет существовать.

Есть способы сделать это:

  1. использовать временные файлы (или FIFO)

    tmpfile=$(mktemp)
    >"$tmpfile"  produce_the_data
    <"$tmpfile"  while read ...; do count[x]=y; ...; done
    
  2. установитьlastpipe опция оболочки

    set +m
    shopt -s lastpipe
    produce_the_data | while read ...; do count[x]=y; ...; done
    
  3. использовать замену процесса:

    while read ...; do count[x]=y; ...; done < <(produce_the_data)
    # .......................................^.^^................^
    #                                        | |
    # typical redirection -------------------+ |            
    # process substitution acts like a file ---+
    
0 голосов
/ 31 мая 2018

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

awk -F' *[AB]: *' '{a[$2","$3]++;next}END{print "A","B","Count";for(i in a){print i,a[i]}}' OFS=',' file | column -t -s','

-F опция устанавливает разделитель либо A: или B:.

Массив a, заполненный числом B вхождения строки.

Оператор END печатает заголовок и цикл по массиву для печати строки и счетчика.

Наконецкоманда column выводит результат в виде таблицы.


В ответ на последнее изменение OP, возможный путь вперед - определить строку с помощью опции -v и просмотреть эту строку с помощью ~ команда регулярных выражений.

awk -F' *[AB]: *' -v h1="Hello World" -v h2="Hello" -v h3="Hi there" '$3~h1{a[$2","h1]++;next}$3~h2{a[$2","h2]++;next}$3~h3{a[$2","h3]++;next}END{print "A","Key","Count";for(i in a){print i,a[i]}}' OFS=',' file | column -t -s','
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...