用于 Semver 匹配的 GNU grep 正则表达式

GNU grep regex for Semver matching

我有一个 URL,我正在尝试提取 Semver 的一部分。 Semver 的格式为 2.x.0(如果有帮助,它将始终为 2.x.0)。我需要 x 值,在我的例子中它是 15290.

我正在使用 GNU grep。这是我目前所拥有的:

$echo "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz" |  grep -oP '(?<=[.])\d+(?=[.0])'

(?<=[.]) is a look behind. It matches, in this case, just after a period.

\d+ matches any number of digits characters.

(?=[.0]) is a look ahead. It matches, in this case, just before a period 0.

我得到的输出是

15290
15290
0

我认为 0 匹配是因为 foo_bar-2.15290.0.tar.gz。有更好的方法吗?不知道我的逻辑对不对

您可以扩展环视以使其更具体并匹配例如以下 /

(?<=\d[.])\d+(?=\.\d+/)

Regex demo

echo "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz" |  grep -oP '(?<=\d[.])\d+(?=\.\d+/)'

输出

15290

如果 / 并不总是存在,您还可以声明一个 . 和右边的数字,而不是后面再跟一个 .

(?<=\d[.])\d+(?=\.\d+(?!\.))

Regex demo

您的正则表达式 (?<=[.])\d+(?=[.0]) 匹配任何一个或多个以点开头并后跟点或 0 的数字。因此,字符串的 2.15290.0/foo_bar-2.15290.0. 部分具有三个有效匹配项,15290152900.

你可以使用

grep -oP '.*2\.\K\d+(?=\.0\b)' <<< "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz"

regex demo and the online grep demo详情:

  • .* - 除换行字符外的任何零个或多个字符,尽可能多(这使得 grep return 最后一次出现匹配项)
  • 2\. - 2. 字符串
  • \K - 匹配重置运算符丢弃目前匹配的文本
  • \d+ - 一位或多位数字
  • (?=\.0\b) - 要求 .0 后没有字符字符立即出现在当前位置右侧的前瞻。

以防万一你想使用 awk:

url="https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz"
awk 'match([=11=],/2\.[0-9]+\.0/){print substr([=11=],RSTART+2,RLENGTH-4)}' <<< "$url"

online demo。找到 2\.[0-9]+\.0 模式并从第三个字符减去最后两个字符打印它的一部分。

第一个解决方案: 使用您显示的示例,您可以尝试遵循 awk。只需根据显示的示例将字段分隔符设置为 /|\.tar|-,然后打印倒数第二列。

echo "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz" | 
awk -F'/|\.tar|-' '{print  $(NF-3)}'

第二个解决方案: 以更有效的方式使用 match 函数,其他答案的匹配可能会失败,因为那是 运行 在整行上,以防在同一行上找到更多匹配项,但这将在现场显示样本。

echo "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz" |
awk -F'/' 'match($NF,/-[0-9]+\.[0-9]+\.[0-9]+\.tar\.gz/){print substr($NF,RSTART+3,RLENGTH-12)}'

第三个解决方案: 在这里使用 GNU grep,它将专门查找路径的最后一个值并打印版本按照它。

echo "https://example.com/repository/local/foo-bar/2.15290.0/foo_bar-2.15290.0.tar.gz" |
grep -oP '.*/.*?-\d+\.\K\d+(?=\.\d+)'