shell Grep条件在看似应该正确匹配时未正确匹配

xmakbtuz  于 2023-05-01  发布在  Shell
关注(0)|答案(2)|浏览(130)

我正在尝试创建一个bash脚本,其中greps通过2个文件:我的根包锁。json文件和e2e子文件夹中的一个。
我希望脚本显示它找到的以"resolved": "http开头的字符串的数量
然后,我希望检查这些字符串中的每一个字符串,以确保它们以"resolved": "https://nexus.com/repository/myrepo开头
这是我得到的

#!/bin/bash

ROOT_LOCKFILE="../package-lock.json"
E2E_LOCKFILE="../e2e/package-lock.json"

matches=$(grep '^ *"resolved": "http' "$ROOT_LOCKFILE" "$E2E_LOCKFILE")
echo "$matches" | wc -l

if [[ $matches == '"resolved": "https://nexus.com/repository/myrepo'* ]]; then
  echo "All strings start with \"resolved\": \"https://nexus.com/repository/myrepo"
  echo 0
else
  echo "Not all strings start with \"resolved\": \"https://nexus.com/repository/myrepo"
  exit 1
fi

echo "$matches" | wc -l给了我一个数字,我已经通过在Visual Studio中手动搜索"resolved": "http引用来确认这两个文件是正确的。
当我将VS上的搜索扩展为"resolved": "https://nexus.com/repository/myrepo时,我得到了完全相同的数字。
所以这告诉我所有包含"resolved": "http的引用也都以"resolved": "https://nexus.com/repository/myrepo开头
但是我的脚本进入else语句,而不是像我预期的那样工作。
我做错了什么?

vwoqyblh

vwoqyblh1#

命令

[[ $matches == '"resolved": "https://nexus.com/repository/myrepo'* ]]

为true(退出代码为零),如果变量matches

"resolved": "https://nexus.com/repository/myrepo

matches的第一个字符必须是双引号字符。
但是,在grep命令中,您向grep传递了两个文件名。在这种情况下,grep 的每一行都将以匹配文件的名称开始。因此,此条件将失败。
您可以通过使用选项-h来摆脱文件名,但即使这样也不能保证它能正常工作。毕竟,你的grep模式以^ *开始,这意味着一个匹配的行可以在开始处有一个空格,这也不同于双引号。
实际上,你的代码告诉我你只对两件事感兴趣:

- How many matches do we have?
- Produce a message dependend on whether the number of  matches is 0 or non-zero

我会直接把它翻译成代码:

nmatches=$(cat  "$ROOT_LOCKFILE" "$E2E_LOCKFILE"|grep -c '^ *"resolved": "http')

if ((nmatches > 0))
then
  echo we have matches
else
  echo no match
fi

请注意,我使用cat,以便grep将输入视为一段文本,而-c计算匹配行的总数。这对应于wc -l的用法。

8oomwypt

8oomwypt2#

如果你想做的只是确保所有的匹配都不是你期望的值,那么这很简单-

if grep -Pq '[[:space:]]*"resolved": "http(?!s://nexus.com/repository/myrepo)' "$ROOT_LOCKFILE" "$E2E_LOCKFILE"
then echo 'Not all strings start with "resolved": "https://nexus.com/repository/myrepo"
     exit 1
fi

但是,如果没有正面的命中,这可能会产生误导。
如果你需要验证你期望的字符串是否有有效的命中,它需要额外的一个或两个步骤。

matches=$( grep '[[:space:]]*"resolved": "http'  "$ROOT_LOCKFILE" "$E2E_LOCKFILE" )

if   grep -Pq '[[:space:]]*"resolved": "http(?!s://nexus.com/repository/myrepo")' <<< "$matches"
then echo 'Not all strings start with "resolved": "https://nexus.com/repository/myrepo"'
     exit 1
elif grep '[[:space:]]*"resolved": "https://nexus.com/repository/myrepo"' <<< "$matches"
then echo 'All strings start with "resolved": "https://nexus.com/repository/myrepo"'
     echo 0
else echo "There were no matches!"
     exit 1
fi

如果matches的文件比较小,可以跳过pre-grep,但是如果它们很大,最好将结果集放入字符串或临时文件中,所以我保留了它。

相关问题