shell 使用Regex的Grep:在一定范围内查找一个单词后跟一个数字

ht4b089n  于 2023-04-21  发布在  Shell
关注(0)|答案(2)|浏览(148)

这似乎是一个相当简单的要求,但我发现它相当难以解决。
我有一个文件,“results.json”,它看起来像这样(简化):

{
          "policyId" : "pol1",
          "policyName" : "Security-High",
          "threatLevel" : 7,
          "policyViolationId" : "high",
},
{
          "policyId" : "pol2",
          "policyName" : "Security-Low",
          "threatLevel" : 1,
          "policyViolationId" : "low",
},
{
          "policyId" : "pol3",
          "policyName" : "Security-High",
          "threatLevel" : 10,
          "policyViolationId" : "high",
}

我想扫描文件,然后如果它发现任何名为"threatLevel" :后跟7,8,9或10的东西,我希望脚本报告它。
使用grep在任何类型的正则表达式检查中实现“7-10”都很困难。
这是我迄今为止通过bash shell脚本所尝试的:

工作,但看起来有点不整洁

if grep -q "threatLevel\" : 7\|threatLevel\" : 8\|threatLevel\" : 9\|threatLevel\" : 10" "$FILE"; then
    echo 'threshold string does exist';
else   
    echo 'threshold string does not exist';
fi

*Output: threshold string does exist*

工作,但宁愿不使用精灵,因为它不是一个完全不同的情况

if grep -q "threatLevel\" : [7-9]" "$FILE"; then
    echo 'threshold string does exist';
elif grep -q "threatLevel\" : 10" "$FILE"; then
    echo 'threshold string does exist';
else   
    echo 'string does not exist for regex 7-10';
fi

*Output: threshold string does exist*

不管用为什么

if grep -q "threatLevel\" : ([7-9]|10)" "$FILE"; then
    echo 'threshold string does exist';
else   
    echo 'threshold string does not exist';
fi

*Output: threshold string does not exist*
cdmah0mi

cdmah0mi1#

不是grep解决方案,但如果您有有效的JSON(或JSON-nd)输入,grep可能不是最好的解决方案。jq是一个解析,过滤和转换JSON文档的命令行工具。
给定以下输入(经过清理以包含有效JSON文档流):

{
          "policyId" : "pol1",
          "policyName" : "Security-High",
          "threatLevel" : 7,
          "policyViolationId" : "high"
}
{
          "policyId" : "pol2",
          "policyName" : "Security-Low",
          "threatLevel" : 1,
          "policyViolationId" : "low"
}
{
          "policyId" : "pol3",
          "policyName" : "Security-High",
          "threatLevel" : 10,
          "policyViolationId" : "high"
}

然后使用下面的jq调用为您提供具有给定威胁级别的所有对象:

$ jq 'select(.threatLevel | . >= 7 and . <= 10)' results.json
{
  "policyId": "pol1",
  "policyName": "Security-High",
  "threatLevel": 7,
  "policyViolationId": "high"
}
{
  "policyId": "pol3",
  "policyName": "Security-High",
  "threatLevel": 10,
  "policyViolationId": "high"
}

如果您只想获取威胁级别属性/行,则必须使用稍微不同的过滤器:

$ jq -r '.threatLevel | select(. >= 7 and . <= 10) | "\"threatLevel\": \(.)"' results.json
"threatLevel": 7
"threatLevel": 10

或者只获得水平:

$ jq '.threatLevel | select(. >= 7 and . <= 10)' results.json
7
10

您在if中使用grep,因此您也可以使用jq将(固定的)JSON文档转换为值truefalse(并设置退出代码):

if jq -e 'any(.threatLevel | . >= 7 and . <= 10)' >/dev/null; then
  echo 'threat level 7-10 found';
else
  echo 'threat levels not found';
fi

为什么是jq而不是grep呢?jq可以正确地处理输入,例如:

"threatLevel"    :     7

"threatLevel":7

甚至

"threatLevel"
:
7
kiayqfof

kiayqfof2#

这将查找从7到9的个位数,或10。

grep '"threatLevel" : \([7-9]\|10\)'

由于转义,您的尝试失败。Grep默认使用POSIX基本正则表达式,因此许多控制字符都需要转义。

相关问题