我目前正在尝试使用bash从文件名中提取子字符串和版本号。
文件名有两种格式:
example-substring-1.1.0.tgz
example-substring-1.1.0-branch-name.tgz
字符串
对于第一个场景,我可以使用sed提取版本号,如下所示:
echo example-substring-1.1.0.tgz | sed "s/.*-\(.*\)\.[a-zA-Z0-9]\{3\}$/\1/"
型
但这对第二种情况不起作用。
最后,我想创建一个脚本,将第一个子字符串和版本存储在一个关联数组中,如下所示。
example_array["example-substring"]="1.1.0"
example_array["example-substring"]="1.1.0-branch-name"
型
这是棘手的,但是,我似乎找不到一个好的方法,将两种情况下工作。和场景的版本包括分支名称,我不能事先知道有多少个字的分支名称将组成。
我认为变量扩展可能是要走的路,但不能让它输出我想要的。
如果你能帮忙的话,我将不胜感激。
5条答案
按热度按时间oug3syen1#
为了能够真正测试这一点,我们需要包含更多问题案例的样本输入,例如,像
-1.2.3
这样的字符串看起来像是出现在分支名称中的版本号:字符串
通常我会在sed或awk中进行模式匹配,例如使用任何awk:
型
而不是一个shell循环,但因为你想用结果填充一个shell数组:
型
型
vu8f3i0k2#
用Perl
字符串
打印两个字
型
因此,这是它返回到shell脚本,我假设这将被调用,然后可以在shell脚本中形成所需的结构。†测试也没有分支名称,并使用输入字符串的一些其他变体。
由于
example-substring
也可以包含数字(为什么不呢?),分支名称也可以(为什么不呢?),因此正则表达式模式没有任何限制,并且前导和(可能的)尾部都可以简单地由.+
和.*
匹配。但是我们需要更具体的版本号,我使用了一个假设,它总是由 * 3 * 个用点分隔的数字组成。我还假设了字符串的固定其余部分,文件扩展名
.tgz
。如果需要,这些可以放宽一些。†可以直接将列表(键值键值...)读入关联数组
型
或者先给变量赋值可能更合适
型
或者仅仅使用位置参数
型
当然,还有其他方法可以将参数传递给Perl脚本或命令行程序(“一行程序”),以及其他方法可以在bash中获取其输出。
如果这段Perl代码需要注解,请告诉我。
ryevplcw3#
如果您愿意使用
grep
而不是sed
,那么lookaheads和lookbehinds将允许您定义模式来提取您关心的内容。考虑一下这个模式:
.+(?=-\d+\.\d+\.\d+)
这将匹配任何后跟-<numbers>.<numbers>.<numbers>
的内容。?=
标记一个条件先行,这是一个必须匹配下一个字符的表达式,但被排除在模式的最终匹配之外。当与您的示例一起使用时:字符串
(The
P
标志启用PCRE 2,o
标志仅打印匹配项)还考虑模式:
(?<=-)\d+\.\d+\.\d+.*(?=\.tgz$)
它使用lookbehinds来Assert,紧接在模式之前,有一个-
,并使用lookaheads来Assert模式以.tgz
结束。当用于您的示例时:型
brqmpdu14#
这可能对你有用(GNU sed):
字符串
匹配文件名,其中包含一个或多个由
-
分隔的单词,后跟由.
分隔的数字,然后以.
开头的扩展名结束,并返回由.
分隔的数字。gfttwv5a5#
使用Bash内置的模式匹配,你可以做你需要做的事情。这个Shellcheck-clean代码演示了这个想法:
字符串
这将产生:
型
shopt -s extglob
启用“扩展globbing”(包括像+([0-9])
这样的模式)。请参阅glob - Greg's Wiki中的extglob部分。${f%.*}
、${base%%-+([0-9]).*}
和${base#"$substring-"}
的解释,请参阅删除字符串的一部分(BashFAQ/100(如何在bash中进行字符串操作?))。declare -p var
以一种明确的方式打印变量的值。在打印两种数组的值时,它避免了循环和陷阱。