从固定模式字符串中提取多个值

7

我想从wget命令输出的最后一部分解析出3个信息片段。例如:

2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]

我能够获取日期/时间,因为它是固定长度的。但我无法提取预估传输速度(13/7)和文件大小(1077022)的值。

STR="2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]"
echo date/time is ${STR::19}

我想剩余的子字符串提取需要使用正则表达式的帮助来完成,但我无法弄清楚。是否有一种可行的方法仅使用*nix工具,如awk、sed等?

我尝试了awk:

echo "(13.7 Mb/s)" | awk '$0 ~ /(.* Mb\/s)/ {print $1}'

但我得到的是(13.7,而不仅仅是数字。

5个回答

8
你可以使用bash的正则表达式匹配,使用( )来捕获相关部分,使用${BASH_REMATCH[n]}来获取它们:
str="2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]"

pattern='([-0-9]+ [:0-9]+) \(([^)]+)\) .*\[([0-9]+)\]'
if [[ "$str" =~ $pattern ]]; then
    echo "date/time is ${BASH_REMATCH[1]}"
    echo "transfer speed is ${BASH_REMATCH[2]}"
    echo "file size is ${BASH_REMATCH[3]}"
else
    echo "The string is not in the expected format"
fi

顺便提一下,我建议使用小写或混合大小写的变量名称,以避免与具有特殊功能的许多全大写名称冲突,并将您的脚本通过shellcheck.net查找常见错误。


6
这个 awk 应该适合你的需求:
s="2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]"
awk -F '[][()[:blank:]]+' '{
  printf "DateTime: %s %s, Speed: %s, Size: %s\n", $1, $2, $3, $(NF-1)
}' <<< "$s"

DateTime: 2022-12-26 19:14:44, Speed: 13.7, Size: 1077022

说明:

  • -F '[][()[:blank:]]+'将一个或多个字符[]() 或空格设置为输入字段分隔符

我得到了输出 DateTime: 2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022] , Speed: , Size: 2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022] - Web User
请查看此工作演示:https://ideone.com/8D7QXp - anubhava

6

请使用您提供的示例,尝试以下awk代码。 该代码已在GNU awk中编写并测试。 此处是用于所使用正则表达式的在线演示

s="2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]"

awk '
match($0,/([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) \(([^)]*).*\[([0-9]+)/,arr){
  print "DateTime: "arr[1] ", Speed: " arr[2] ", Size: "arr[3]
}
' <<< "$s"

在线演示可以正常运行,但上述代码会抛出错误“awk: line 2: syntax error at or near ,”。 - Web User
@WebUser,这是在GNU awk中测试过的代码。请您确认一下您的awk版本,运行一次awk -v命令并查看它的输出,祝福您。 - RavinderSingh13

5

使用 Perl 和 命名捕获组

s="2022-12-26 19:14:44 (13.7 Mb/s) - ‘somelibrary.min.js’ saved [1077022]"

perl -nE '
    say join "\n",
    map { "$_: $+{$_}" }
    keys %+
    if m/
        (?<dateTime>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\(
        (?<speed>\d+\.\d+).*\[
        (?<size>\d+)
    /x
' <<< "$s"

输出

speed: 13.7
dateTime: 2022-12-26 19:14:44
size: 1077022

解释

请参见regex101描述


3

在替换操作中,使用sed和三个捕获组\1\2\3

sed -E 's/([^()]+) \(([^()]*)\).*\[([^][]*)]/date\/time: \1\nspeed: \2\nfile size: \3/' file

这种模式匹配:

  • ([^()]+) 捕获第一组,匹配除()之外的任何字符
  • \(([^()]*)\)(...)之间捕获第二组中除了()之外的任何字符
  • .* 匹配行的其余部分
  • \[([^][]*)][...]之间捕获第三组中除了[]之外的任何字符

regex101上查看捕获组的值

输出

date/time: 2022-12-26 19:14:44
speed: 13.7 Mb/s
file size: 1077022

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接