【问题标题】:bash extract version string & convert to version dotbash 提取版本字符串并转换为版本点
【发布时间】:2020-11-27 00:21:27
【问题描述】:

我想从my-app-1_4_5.img 中提取版本字符串(1_4_5),然后转换为不带文件名的点版本(1.4.5)。版本字符串将包含三个 (1_4_5) 或四个 (1_4_5_7) 段。

让这一班轮工作ls my-app-1_4_5.img | cut -d'-' -f 3 | cut -d'.' -f 1 | tr _ .

想知道是否有更好的方法,而不是从cut 管道输出。

【问题讨论】:

  • 如果文件名总是像file-name-x-1_2_3_4.ext,那么你可以简单地echo file-name-x-1_2_3_4.ext | tr _ .
  • 我已经更新了我的 Q。只想要最后的点版本号。没有文件名。
  • Don't parse ls 并且当 shell 具有内置参数扩展和正则表达式匹配时,不要使用外部实用程序。
  • 你能澄清一下版本是否总是三段吗?如果没有,是否可以假设文件名中只有一个由下划线分隔的数字序列(可能包括单个数字)?
  • 我会使用 ls my-app-1_4_5.img | sed 's/^.*-//;s/\..*$//;s/_/./g' 。祝你好运。

标签: linux string bash sh


【解决方案1】:

你可以用 sed 做到这一点:

sed -E "s/.*([0-9]+)_([0-9]+)_([0-9]+).*/\1.\2.\3/" <<< my-app-1_4_5.img

【讨论】:

  • 我建议使用 -E 而不是 -r :它适用于现代 GNU sed 和 BSD sed,并且与 grep 使用相同的标志切换到ERE 正则表达式的味道
  • 这将仅涵盖具有三个位置的固定版本。 1_21_2_3_4 之类的呢?
  • @accdias OP 应该清楚地澄清这一点,因为如果你想尽可能通用,你也必须匹配单个数字,我觉得这会产生很多误报
【解决方案2】:

假设版本号总是在最后一个破折号和文件扩展名之间,你可以在纯 Bash 中使用这样的东西:

name="file-name-x-1_2_3_4_5.ext"
version=${name##*-}
version=${version%%.ext}
version=${version//_/.}
echo $version

上面的代码会导致:

1.2.3.4.5

有关上面使用的大括号扩展的完整说明,请查看Bash Reference Manual: 3.5.1 Brace Expansion

【讨论】:

  • 链接到 ABS 是可疑的恕我直言。有时它是某个主题的唯一广泛来源,但即便如此,我还是想提出警告。通常你可以找到更少混乱和更简洁的阐述。
【解决方案3】:

这是一个参数扩展的尝试。我假设您有一个要循环的通配符模式。

for file in *-*.img; do
    base=${file%.img}
    ver=${base##*-}
    echo "${ver//_/.}"
done

构造${var%pattern} 返回变量var,并去掉任何匹配pattern 的后缀。同样,${var#pattern} 修剪任何匹配pattern 的前缀。在这两种情况下,将运算符加倍会切换到修剪可能最长的匹配而不是最短匹配。 (这些是 POSIX 兼容的 pattenr 扩展,即不严格仅限 Bash。)构造 ${var/pattern/replacement}pattern 上的 var 中的第一个匹配替换为 replacement;将第一个斜线加倍会导致每个匹配项都被替换。 (这仅适用于 Bash。)

【讨论】:

  • 这不是和我的答案几乎一样吗?为什么要复制它?
  • 我们几乎同时回答。如果你想从这里复制解释部分,我会删除我的。
  • 不...不用担心。
【解决方案4】:

删除除0 之外的所有内容到9_ 和换行符,然后将所有_ 替换为.

echo "my-app-1_4_5.img" | tr -cd '0-9_\n' | tr '_' '.'

输出:

1.4.5

【讨论】:

  • 这适用于my-app-1_4_5.imgmy-app-1_4_5_6.imgmy-app-1_4_55_6.imgmy-app-new-1_4_55_6.imgmy-app-new-6.imgmy-app-new-55_6.img
  • @roy 请注意,如果您的文件包含不属于版本的数字,这将失败,例如 fail2ban-1_4_5.img 将产生 21.4.5 而不是预期的 1.4.5。这并不是说这个解决方案不好,这里的每个答案都有其局限性
【解决方案5】:

使用 bash 和正则表达式:

echo "my-app-1_4_5.img" | while IFS= read -r line; do [[ "$line" =~ [^0-9]([0-9_]+)[^0-9] ]] && echo "${BASH_REMATCH[1]//_/.}"; done

输出:

1.4.5

【讨论】:

    【解决方案6】:

    略短的变体

    name=my-app-1_4_5.img
    vers=${name//[!0-9_]}
    $ echo ${vers//_/.}
    1.4.5
    

    【讨论】:

    • 当你有name=123-my-app-1_4_5.img之类的东西时,你检查过你的代码做什么吗?
    • @accdias 显然我的解决方案没有涵盖这种情况,它只是一个快速破解)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 2015-04-13
    • 1970-01-01
    • 2015-09-04
    • 1970-01-01
    • 2016-11-18
    • 2020-07-30
    相关资源
    最近更新 更多