我有一个 JSON 格式的大日志文件,其中包含一行,如下例所示:
{"data_1":210,"target_number":1096748811,"extra_data":66}
{"data_1":0,"target_number":7130881445,"extra_data":56}
{"data_1":1712,"target_number":1098334917,"extra_data":48}
{"data_1":0,"target_number":3062674667,"extra_data":54}
{"data_1":53,"target_number":5110609228,"extra_data":246}
我想target_number
用整个文件中的 MD5 哈希值替换 的值。
我正在尝试使用sed
以下基本语法的命令:
sed -i 's/target_number/target_number_md5/' input.log
预期输出(对于上例中的第一个条目)是:
{"data_1":210,"target_number":620e25e6f054992308c564cb883e4940,"extra_data":66}
答案1
以下命令使用磨坊主( mlr
) 来解析 JSON 输入(Miller 版本 6 或更高版本应使用--jsonl
来--json
读取“JSON 行”)。然后它使用put
子命令来修改键的值target_number
。修改是通过openssl md5
使用标准输入上传递的原始值进行调用来完成的。然后,我们通过从响应中删除除 MD5 哈希值之外的所有内容来清理生成的字符串。
mlr --json put '
$target_number = system("printf \"" . $target_number . "\" | openssl md5");
$target_number = sub($target_number, ".*= ", "")' file
如果您想使用md5sum
GNU coreutils,请将openssl md5
上面的替换为md5sum --tag
.
通过使用md5
实用程序(通常在 BSD 系统上找到),我们可以避免printf
管道:
mlr --json put '
$target_number = system("md5 -s \"" . $target_number . "\"");
$target_number = sub($target_number, ".*= ", "")' file
鉴于问题中的示例,上述每个命令的输出如下:
{ "data_1": 210, "target_number": "620e25e6f054992308c564cb883e4940", "extra_data": 66 }
{ "data_1": 0, "target_number": "f83d74be3dcb71d53263aefdf08203a9", "extra_data": 56 }
{ "data_1": 1712, "target_number": "56ae797ad2c16813d1a6168d28b58d89", "extra_data": 48 }
{ "data_1": 0, "target_number": "81394a193503036fad53b8a9d6ca2456", "extra_data": 54 }
{ "data_1": 53, "target_number": "6f01490a5dc694e51a69b79f7dd21c24", "extra_data": 246 }
由于 MD5 哈希值是字符串,而不是十进制数字,因此它们会作为字符串插入到生成的 JSON 文档中。
mlr
如果您使用其选项,Miller 可以用生成的文档替换输入文件(即进行“就地”编辑)-I
。
target_number
请注意,上面的每个命令都在调用中使用原始值system()
而不对其进行清理,这样做会构成代码注入漏洞。
答案2
解决类似的问题,我发现了这个问题。提供的解决方案对我来说不太有效,因为我想在没有循环的情况下解决它。
下面是如何在没有循环的情况下解决问题的概念证明:
sed -E 's/(.*target_number":)([0-9]+)(.*)/echo "\1$(echo -n \2 | md5sum)\3"/e;s/ -//' "$inputFile"
-E
:使用扩展正则表达式而不是基本正则表达式。/e
:该命令允许将 shell 命令的输入通过管道传送到模式空间。
有关更多详细信息,请检查此来源:https://www.gnu.org/software/sed/manual/sed.html
答案3
我自己找到了答案。
cat $inputFile | grep -Po '(?<="target_number":)[^,"]+' | while read i ; do
sed -i "s/$i/$(echo -n $i | md5sum | cut -f 1 -d ' ')/g" $outputFile
done