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

#grep

#grep

Вопрос:

У меня есть набор из многих .json.gz файлов. В каждом файле есть записи, подобные этой:

 {"type":"e1","public":true, "login":"username1", "org":{"dict","of":"lots_of_things"}}
{"type":"e2","public":true, "login":"username2"}
  

Независимо от того, где в каждом вложенном dict появляется «login», я хочу иметь возможность обнаруживать его и принимать имя пользователя, только если ключ «org» нигде не существует во вложенном dict. Я также хочу подсчитать, сколько раз каждое имя пользователя появляется в файлах.

Моим конечным результатом должен быть файл dicts, который выглядит следующим образом:

 {'username2: 1}
  

потому что, конечно, username1 не будет учитываться: ключ «org» появляется в его dict.

Я ищу что-то вроде:

 zgrep -Rv "org" . | zgrep -o 'login":"[^"]*"' /path/to/files/* | cut -d'"' -f3 | sort | uniq -c | sed '1i{
       s/s*([0-9]*)s*(.*)/"2": 1,/;$a}' > outputfile.txt
  

Я не уверен в этой части:

 zgrep -Rv "org" . | 
  

Остальные успешно создают тип файла, который я ищу. Я просто не уверен в порядке операций здесь.

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

Я должен был быть более ясным, я прошу прощения. Также часто существует несколько экземпляров ключа «login» для каждого основного объекта dict. Например (используя «k» для любого ключа, который не является login и не org, и используя «v» для значения):

 {"k":"v","k":{"k":{"k":"v","login":"username1"},"k":"v"},"k":{"k":"v","login":"username2"}}
{"k":{"k":"v","k":"v"},"k":{"org":{"k":"v","k":v,"login":"username3"},"k":"v"},"k":{"k":"v","login":"username4"}}
{"k":{"k":"v"},"k":{"k":{"k":"v","login":"username1"},"login":"username2"}}
  

Поскольку ключ org появляется во втором дикте, я хочу исключить имена пользователей 3 и 4 из дикта, который я создаю, и сохранить в файл.

Например, я хочу, чтобы это было в файле:

 {'username1': 2}
{'username2': 2}
  

Комментарии:

1. Вы пробовали анализировать JSON с помощью синтаксического анализатора, такого как jq ? Также можете ли вы предоставить действительный образец JSON, чтобы я мог порекомендовать способ использования jq для него

2. Дело в том, что они на самом деле не являются допустимыми файлами json, насколько я понимаю. Формат соответствует тому, который я дал. Чтобы быть допустимым json, я думаю, у меня не может быть вложенных dicts, но это то, что у меня есть.

Ответ №1:

Решение AWK и замена find -R на более надежный find:

 find . -type f -name "*.json.gz" -print0 | xargs -0 zgrep -v -h '"org"' | awk '{ if ( match($0,/"login":"[^"] "/) ) logins[substr($0,RSTART 8,RLENGTH-8)]  ; } END { for ( i in logins ) print("{" i ":" logins[i] "}"); }'
  

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

 {"username2":1}
  

Ответ №2:

не grep, а задание gnu sed со сценарием, ваши данные в ‘a’

 i=
for e in $(sed -nE '/.*borgb.*/!s/.*"login":"(w )".*/{1:}/p' a)
{
let i  ;echo ${e/:/:$i}
}
  

используйте ‘>’ в конце для сохранения в файле

если установлено лучшее регулярное выражение: ‘pcregrep’, оно также работает;

 pcregrep -io '(?!.*borgb.*)(?<="login":")w (?=".*)' a
  

замените приведенный выше сценарий sed … на немного скорректированную распечатку

Ответ №3:

Это сработало:

 zgrep -v "org" *.json.gz | zgrep -o 'login":"[^"]*"' | cut -d'"' -f3 | sort | uniq -c | sed '1i{
       s/s*([0-9]*)s*(.*)/"2": 1,/;$a}' > usernames_2011.txt