删除目录中多个文本文件的特定字符串之后的所有文本

删除目录中多个文本文件的特定字符串之后的所有文本

我有大约 25,000 个 JSON 文件需要验证和检查,我注意到一些文件已经重复,导致使用 Excel 将 JSON 转换为 CSV 时出现错误。

我试图删除之后的所有字符串,"version":"0.2.3"}因为这表明 JSON 的结尾,然后再重复,"version": "0.2.3"}{"analysis": {因此我需要保留"version": "0.2.3"}并删除{"analysis": {其后面的所有内容,并将这些更改应用到所有 25,000 个文件。我见过有人使用 grep 和 sed 但我自己似乎无法让它们工作。

如果有人可以提供帮助,我将不胜感激,因为手动删除文本是不可取的,所以我希望在 bash 或其他东西中有一个衬垫!

下面是我需要修复的内容(其中一个文件的精简版本),下面是所需的输出。正如您所看到的,无论出于何种原因,JSON 数据可能会在 API 使用过程中自我复制。

有问题的输入(已修剪json):

{"analysis":{"score":3},"sample":{"completed":"2022-01-27T21:22:21Z","created":"2022-01-27T21:17:57Z","id":"220127-z5h84saffl","md5":"7871a75734af389b787bad57a3ea087d","score":3,"sha1":"58a8689ee76a46559ea56a52d20425f44c8ff601","sha256":"23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"},"version":"0.2.3"}{"analysis":{"score":3},"sample":{"completed":"2022-01-27T21:22:21Z","created":"2022-01-27T21:17:57Z","id":"220127-z5h84saffl","md5":"7871a75734af389b787bad57a3ea087d","score":3,"sha1":"58a8689ee76a46559ea56a52d20425f44c8ff601","sha256":"23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"},"version":"0.2.3"}

期望的输出:

{"analysis":{"score":3},"sample":{"completed":"2022-01-27T21:22:21Z","created":"2022-01-27T21:17:57Z","id":"220127-z5h84saffl","md5":"7871a75734af389b787bad57a3ea087d","score":3,"sha1":"58a8689ee76a46559ea56a52d20425f44c8ff601","sha256":"23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"},"version":"0.2.3"}

答案1

使用jq(适用于大多数类 Unix 系统),您可以从文件中提取第一个 JSON 对象并使用以下命令丢弃其余对象

jq -n 'input' file >newfile

这会生成“打印精美”的 JSON。使用该-c选项可以获得“紧凑”输出(具有最少空白的单行)。输出写入到newfile.

jq指令input生成下一个可用的 JSON 对象。我们使用-n( --null-input)关闭数据的默认读取,并用于input仅处理输入文件中的第一个对象。

对于问题中给定的数据,这会产生

{
  "analysis": {
    "score": 3
  },
  "sample": {
    "completed": "2022-01-27T21:22:21Z",
    "created": "2022-01-27T21:17:57Z",
    "id": "220127-z5h84saffl",
    "md5": "7871a75734af389b787bad57a3ea087d",
    "score": 3,
    "sha1": "58a8689ee76a46559ea56a52d20425f44c8ff601",
    "sha256": "23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"
  },
  "version": "0.2.3"
}

然后简单地用结果覆盖原始文件。单个文件的完整处理可能看起来像

jq -n 'input' file >newfile &&
mv newfile file

假设您的文件位于当前目录中并匹配某些模式*.json,那么您可以在简单的 shell 循环中处理所有文件,如下所示:

for name in *.json; do
    cp -- "$name" "$name.orig" &&
    jq -n 'input' <"$name.orig" >"$name"
done

这与我刚才展示的有点不同,将原始内容保留在带有.orig文件名后缀的文件中,并确保原始文件的元数据(权限等)不被更改。一旦确定这样做正确,您就可以删除带有.orig文件名后缀的文件。

始终在正确备份的数据上进行此类测试。


您还提到将这些文件转换为 CSV,但没有提及您需要什么。假设您可能希望sample数据为 CSV 格式,并以键作为标题:

jq -n -r 'input | .sample | keys, [.[]] | @csv' file

需要选项 ( ) 来为您提供解码后的数据,而不是 JSON字符串-r--raw-output

对于给定的文档,这会给你

"completed","created","id","md5","score","sha1","sha256"
"2022-01-27T21:22:21Z","2022-01-27T21:17:57Z","220127-z5h84saffl","7871a75734af389b787bad57a3ea087d",3,"58a8689ee76a46559ea56a52d20425f44c8ff601","23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"

答案2

使用(以前称为 Perl_6)

示例输入(错误的 JSON):

~$ cat file.json
{"analysis":{"score":3},"sample":{"completed":"2022-01-27T21:22:21Z","created":"2022-01-27T21:17:57Z","id":"220127-z5h84saffl","md5":"7871a75734af389b787bad57a3ea087d","score":3,"sha1":"58a8689ee76a46559ea56a52d20425f44c8ff601","sha256":"23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"},"version":"0.2.3"}{"analysis":{"score":3},"sample":{"completed":"2022-01-27T21:22:21Z","created":"2022-01-27T21:17:57Z","id":"220127-z5h84saffl","md5":"7871a75734af389b787bad57a3ea087d","score":3,"sha1":"58a8689ee76a46559ea56a52d20425f44c8ff601","sha256":"23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a"},"version":"0.2.3"}

示例输出(Raku 的哈希格式):

~$ cat file.json | raku -MJSON::Stream -e 'my @a;  \
   react whenever json-stream($*IN.Supply, [q[$], *][0],) {@a.push($_.values)};  \
   "\n".print; .say for @a.[0].hash;'

sample => {completed => 2022-01-27T21:22:21Z, created => 2022-01-27T21:17:57Z, id => 220127-z5h84saffl, md5 => 7871a75734af389b787bad57a3ea087d, score => 3, sha1 => 58a8689ee76a46559ea56a52d20425f44c8ff601, sha256 => 23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a}
version => 0.2.3
analysis => {score => 3}

上面,可以使用 Raku 的模块读入不完整的 JSON JSON::Stream,因为它是一个 JSON 流解析器(在到达 EOF 之前解析),所以不会验证 JSON。在这种情况下这是幸运的。使用调用从数组中删除错误的第二个元素@a.[0].hash@a.head.hash也有效)。


最终的格式输出JSON是使用to-json()RakuJSON::Tiny模块的命令完成的。总而言之,这就是我们所做的:

最终 JSON 输出(仅使用 Raku 模块):

~$ cat Jarvis4444.json | raku -MJSON::Stream -MJSON::Tiny -e 'my @a;  \
   react whenever json-stream($*IN.Supply, [q[$], *][0],) {@a.push($_.values)};  \
   "\n".print; to-json(@a.[0].hash).put;'

{ "version" : "0.2.3", "sample" : { "score" : 3, "created" : "2022-01-27T21:17:57Z", "sha1" : "58a8689ee76a46559ea56a52d20425f44c8ff601", "id" : "220127-z5h84saffl", "sha256" : "23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a", "md5" : "7871a75734af389b787bad57a3ea087d", "completed" : "2022-01-27T21:22:21Z" }, "analysis" : { "score" : 3 } }

为了与其他答案进行比较,上面的 JSON 输出可以|通过管道传输jq

{
  "sample": {
    "completed": "2022-01-27T21:22:21Z",
    "score": 3,
    "sha1": "58a8689ee76a46559ea56a52d20425f44c8ff601",
    "md5": "7871a75734af389b787bad57a3ea087d",
    "id": "220127-z5h84saffl",
    "sha256": "23c5dee027c7969aabb5828641c55a005f30fb166a5006dbe3a817f56ca0e32a",
    "created": "2022-01-27T21:17:57Z"
  },
  "version": "0.2.3",
  "analysis": {
    "score": 3
  }
}

[处理多个文件:当然,@Kusalananda 的答案提供了编写 shell 循环来处理多个文件、更正/保存每个文件的充足指导]。

https://github.com/moritz/json
https://github.com/FCO/JSON-Stream
https://raku.org

相关内容