Подбор пар с использованием терминала Linux - PullRequest
1 голос
/ 08 марта 2020

У меня есть файл с именем list.txt, содержащий пару (поставщик, продукт), и я должен показать количество продуктов от каждого поставщика и их названия, используя Linux терминал

Пример ввода:

stationery:paper
grocery:apples
grocery:pears
dairy:milk
stationery:pen
dairy:cheese
stationery:rubber

И результат должен быть примерно таким:

stationery: 3
stationery: paper pen rubber
grocery: 2
grocery: apples pears
dairy: 2
dairy: milk cheese

Ответы [ 3 ]

2 голосов
/ 09 марта 2020

Сохраните ввод в файл и удалите пустые строки. Затем используйте GNU datamash:

datamash -s -t ':'  groupby 1  count 2  unique 2  < file

Выход:

dairy:2:cheese,milk
grocery:2:apples,pears
stationery:3:paper,pen,rubber
1 голос
/ 09 марта 2020

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

< os awk -F: '{ count[$1] += 1; items[$1] = items[$1] " " $2 } END { for (supp in items) print supp": " count[supp], "\n"supp":" items[supp]}'

Сценарий awk более читабелен, если записан в несколько строк:

awk -F: '{ # for each line
  # we use the word before the : as the key of an associative array
  count[$1] += 1               # increment the count for the given supplier
  items[$1] = items[$1] " " $2 # concatenate the current item to the previous ones
}
END { # after processing the whole file
      for (supp in items) # iterate on the suppliers and print the result
        print supp": " count[supp], "\n"supp":" items[supp]
    }
1 голос
/ 08 марта 2020

Следующий конвейер должен выполнить работу

< your_input_file sort -t: -k1,1r | sort -t: -k1,1r | sed -E -n ':a;$p;N;s/([^:]*): *(.*)\n\1:/\1: \2 /;ta;P;D' | awk -F' ' '{ print $1, NF-1; print $0 }'

, где

  • sort сортирует строки в соответствии с тем, что находится перед двоеточием, чтобы упростить последующую обработку
  • крипт c sed соединяет линии с общим поставщиком
  • awk считает позиции для поставщика и распечатывает все соответствующим образом.

Делая это с Только awk, как предполагает KamilCuk в комментарии, будет намного более легкой работой; делать это с sed было бы (для меня) кошмаром. Использование обоих, возможно, глупо, но я наслаждался этим.

Если вам нужно подробное объяснение, пожалуйста, прокомментируйте, и я найду время, чтобы предоставить его.

Вот сценарий sed записать одну команду на строку:
:a
$p
N
s/([^:]*): *(.*)\n\1:/\1: \2 /
ta
P
D

и вот как это работает:

  1. :a - это просто метка, с которой мы можем перепрыгнуть через t est или b команда ранчо;
  2. $p - команда p rint, применяемая только к адресу $ (последняя строка); обратите внимание, что все остальные команды применяются к каждой строке, так как адрес не указан;
  3. N читает еще одну строку и добавляет ее в текущее пространство шаблона, помещая между собой \n ewline; это создает мультилинию в пространстве образца
  4. s/([^:]*): *(.*)\n\1:/\1: \2 /, фиксирующую то, что находится перед первым двоеточием в строке, ([^:]*), а также то, что следует за ним, (.*), избавление от доступных пробелов, *;
  5. ta t оценивается, если предыдущая команда s была успешной, и, если это так, передает управление в строку, помеченную a (т. Е. go для шаг 1);
  6. P печатает ведущую часть мультилинии вплоть до встроенной \n ewline;
  7. D удаляет ведущую часть мультилинии до и включая встроенный \n ewline.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...