查找所有文件中另一个字符串之后出现的所有字符串

查找所有文件中另一个字符串之后出现的所有字符串

我的最终目标是拥有一个脚本来计算所有文件中每个用户名的实例。

用户名是一个字符串,用引号引起来,位于字符串“login”之后。例如,在一个文件中,我可能有:

{"this":"is', {"a":"strange"}, "type":{"of":"object", "but":"please"},
 "go":"withit", "login":"username1"}

{"this":"is', {"login":"username2"}, "type":{"of":"object", "but":"please"},
 "go":"withit"}

在另一个文件中,我可能有:

{"this":"is', {"a":"strange"}, "type":{"of":"object", "but":"please"},
 "go":"withit", "login":"username3"}

{"login":"username1", "please":"gowithit"}

在这种情况下,我想要一个 txt 文件,其中包含一个 dict 对象,其中包含每个用户名在文件中出现的次数:

{"username1": 2, "username2":1, "username3":1}

我读过几本事物得到开始,但我似乎无法将其放在一起。我已经对它进行了伪编码,但我无法从这一点继续前进。

我想我需要分两个阶段来做这件事。

1)获取所有用户名的列表

2)统计每个用户名在所有文件中出现的次数。

对于任务 1):

 grep 'login:' * | sed 's/^.*: //'
#Except I think this gets everything from the line after 'login', which isn't what I want.

对于任务 2):

for all_usernames_in_file:
     stringval = username_read_from_saved_file
     cat * | grep -c $stringval > output.txt

任何人都可以从这里拿走它吗?

编辑:

你的意思是我应该这样做:

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

编辑2:仍然不起作用。我试图通过了解每个命令的作用来进行诊断。

假设我只是从这一部分开始:

grep -o 'login":"[^"]*"' /path/to/dir/* | cut -d'"' -f3 | sort | uniq -c > myfile.txt

现在,myfile.txt一片空白。

我认为该命令正在执行以下操作:

grep -o匹配匹配行的非空部分。

'login":"[^"]*"'是我们想要 grep 匹配的字符串。在中间,匹配not equal to[^"]之后的任何字符,并且表示我们想要任何长度的匹配 - 也就是说,用户名的长度并不重要,我们想要引号之间的所有内容。login":""*

|是一个管道。意思是“然后”

cut -d '"' -f3login":"表示使用分隔符 分割返回的行( 后的所有内容) ",并采用字段 3(即,只是用户名)。

|是一个管道。意思是“然后”

sort用户名

|是一个管道。意思是“然后”

获取唯一的用户名并计算每个用户名出现的次数。

如果我拿那么多,并> myfile.txt在末尾加上 a,那么我最终应该得到一个 txt 文件,其中包含用户名和每个用户名出现的次数。它的格式不会很好,但它会存在。

为什么我没有得到这样的文件?

注意:我搜索.json.gz格式化文件有什么关系吗?我已经让脚本在搜索 时可以工作txt,但不能通过其他格式进行搜索。

答案1

假设您始终将登录名和值放在双引号中,彼此后面没有空格,这是 grep 和计数的构造:

grep -o 'login":"[^"]*"' * | cut -d'"' -f3 | sort | uniq -c

这将生成多次出现的登录列表。

现在我们需要根据它形成您需要的 json 格式。sed能够为您做到这一点:

| sed '1i{
       s/\s*\([0-9]*\)\s*\(.*\)/"\2": \1,/;$a}'

这里sed将放入{块的开头和}结尾,并将uniq输出更改为您期望的 json 格式。

UPD:最后的命令应该是这样的:

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

答案2

获取所有用户名,即与某个关联的所有字符串login要从 a格式良好的 JSON 文档,在不知道文档结构的情况下:

jq -r '..|select(.login?).login' file.json

将其应用于多个 JSON 文件,并对结果进行排序和计数:

jq -r '..|select(.login?).login' *.json | sort | uniq -c

这里使用的表达jq

  • ..:递归遍历所有键和值。
  • select(.login?):选择遇到的包含键的对象login
  • .login:获取该键的值。

你想要的字典,基于上面的jq表达式:

jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' *.json

测试:

$ cat file.json
{"this":"is", "A":{"login":"username2"}, "type":{"of":"object", "but":"please"},
 "go":"withit", "login":"me"}
$ jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' file.json
{
  "me": 1,
  "username2": 1
}

给它相同的文件两次:

$ jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' file.json f
ile.json
{
  "me": 2,
  "username2": 2
}

使用jqwith-c可获得单行紧凑输出。

对于我们的示例文件,jq -sr '[..|select(.login?).login]' file.json将产生

[
  "me",
  "username2"
]

通过这个group_by(.)给出

[
  [
    "me"
  ],
  [
    "username2"
  ]
]

map({key:.[0],value:length})部分给出

[
  {
    "key": "me",
    "value": 1
  },
  {
    "key": "username2",
    "value": 1
  }
]

最后from_entries给出最终结果。

答案3

如何使用以正则表达式匹配为键的 Perl 哈希,您可以使用 JSON 模块进行转换:

$ perl -MJSON -lne '$h{$1}++ for /(?<="login":")(.*?)(?=")/g }{ print encode_json \%h' file1 file2
{"username3":1,"username2":1,"username1":2}

答案4

@rush 使用sed在我的 shell 中不起作用,所以我这样做了

grep -Poh '(?<=login":")[^"]*' json* | sort | uniq -c | awk  -v OFS=': ' 'BEGIN{print "{"}{print $2, $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g;s/:/\":/g;s/^([^{}])/\"\1/g'

sed如果您的 shell 允许您转义并在语句"中打印它们,则可以修改倍数。awk

grep -Poh '(?<=login":")[^"]*' json* | sort | uniq -c | awk  -v OFS=': ' 'BEGIN{print "{"}{print \"$2\", $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g'

我的外壳被第二个脚本awk噎住了。\"不知道为什么,但我确信有人会告诉我。

我也尝试过,jq但是它被 json 文件卡住了。似乎有语法错误

"this":"is' #is written so I edited these to
"this":"is"

也不jq喜欢这个结构

{"a":"strange"} # so I also edited these to
b: {"a":"strange"}

如果原始文件应该与所做的编辑一致,那么就jq可以工作

jq '.login' json* | sort | uniq -c | awk -v OFS=': ' 'BEGIN{print "{"}{print $2, $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g'

相关内容