我有一个名为 users.json 的文件,大小为 3GB,并且是无效的 json。所以我想做的是读取文件的文本内容,并获取我需要的信息,即文件中包含的用户名,并将它们写入 usernames.txt 文件,该文件每行应包含 1 个用户名,其中没有重复项。
json 文件中用户名的格式如下: "username":"someUsername"
如何收集所有用户名,将它们放入文本文件中并确保没有重复?
我已经通过 Node.js 和 PHP 进行了尝试,但还没有任何有效的工作,希望使用 bash 可以完成一些很酷的事情。
文件中包含的数据示例(可能没有太大帮助,因为我已经提到了格式"username":"someUsername"
):
username":"satish_nanded","original_ff_id":"99554"},"100003":{"username":"sweetnamu","original_ff_id":"100003"}},"08fdlhNuZEM1z8q4mQftYUtO7uC3":{"575511":{"username":"lrlgrdnr","original_ff_id":"575511"}},"08fe4Dg7NeOTItq3b9Pi8ORsX5J2":{"59520":{"username":"joneljon","original_ff_id":"59520"}},"08gsZHsbm9Rew4S2IqcbGvD9Fct1":{"724707":{"username":"jacksonc4565","original_ff_id":"724707"}
答案1
您可以使用该grep
命令来匹配所需的模式,并sort
过滤掉重复项。如果您的输入文件是input.json
并且输出是usernames.txt
:
grep -P -o '(?<="username":")[^"]*' input.json | sort -u > usernames.txt
分解一下:
grep
是一个用于匹配文件中正则表达式的命令行实用程序。正则表达式是描述您希望查找的文本片段的有效方法-P
告诉grep
我们使用“Perl 兼容正则表达式”。请注意,grep 的手册页将其描述为“高度实验性”!-o
告诉grep
只输出匹配的文本。默认情况下,grep
只要找到匹配项,通常会输出整行。'(?<="username":")[^"]*'
是正则表达式本身:- 我们将其放在单引号中
'....'
以阻止命令行 shell 尝试解释其中的任何内容 (?<=...)
这就是所谓的后向断言。它表示我们想要"username":"
在其他内容之前进行匹配,但不将其包含在输出中[^"]*
意思是“尽可能多的不是 的字符"
。它可以再次细分:[..]
是一个字符类。此时允许在方括号之间放置任何字符。除非...^"
当您使用插入符号^
作为字符类中的第一个字符时,这意味着不是以下任意字符*
[^"]
表示 0 个或多个前面的项目(在本例中是 的整体)。
- 我们将其放在单引号中
通过管道将sort
用户名按字母顺序排序,带有选项-u
意味着“仅唯一项目”,即没有重复项。
注意:所有这些都假设我们匹配的模式不会出现在文件中的其他任何位置(这似乎不太可能),或者 JSON 本身的损坏不会导致匹配失败(这可能是,我不确定您的文件以何种方式损坏)。
编辑:
由于grep
经常抱怨行太长,并且由于某种原因sed -e 's/,/,\n/'
也无法真正工作,因此该split
命令用于将文件分解为更易于管理的块。
答案2
您似乎有很长的 JSON 记录会中断grep -P
,这是一个替代解决方案:
grep -o '"username":"[^"]*' users.json \
| cut -d '"' -f 4 \
| uniq \
| sort -u \
> usernames.txt
在这里,grep
提取完整的“用户名:值”字段,cut
提取值并uniq | sort -u
使用户名唯一。
uniq
没有必要。对于 3GB 的文件,我希望得到数百万个名字的列表,其中有很多连续的重复项。看似无用的东西uniq |
减轻了sort
部分工作的负担,并且可能会让工作进展得更快。不然就不会痛了