
常用正则匹配:测试工程师的文本处理利器
常用正则匹配:测试工程师的文本处理利器
正则表达式就像是文本世界的瑞士军刀,能够精确地从海量日志中提取我们需要的信息。作为测试工程师,掌握正则表达式能让我们在处理测试数据、分析日志文件时事半功倍。
捕获组:匹配到某一部分
使用\1这样的语法
当在sed命令的替换部分使用\1时,它表示对前面的正则表达式模式中使用括号捕获的内容的引用。
在您提供的命令中,\(.*\)使用括号来捕获一个匹配任意字符(.*)的子模式。这个子模式会匹配以"BW="开头、以"MiB"结尾的文本。使用\1表示要引用这个捕获的内容,即保留匹配的部分。
以下是一个示例来说明这个概念:
假设有以下文本内容:
复制
IOPS: 100, BW=256MiB我们想要提取其中的256MiB部分。可以使用sed命令进行替换操作:
复制
echo "IOPS: 100, BW=256MiB" | sed 's/.*BW=\(.*\)MiB/\1/g'在这个命令中,正则表达式模式.*BW=\(.*\)MiB匹配以BW=开头、以MiB结尾的文本,而括号\(.*\)捕获了匹配的部分,即256。然后,替换部分中的\1将引用这个捕获的内容,即保留了256作为输出结果。
所以,在sed命令中,使用\1可以引用前面正则表达式模式中的捕获内容,从而在替换中使用它。
在看一个稍微复杂一点的例子
文本
Disk stats (read/write):
rbd0: ios=5369207/10, merge=17435/18, ticks=75787776/123, in_queue=38370180, util=100.00%
All clients: (groupid=0, jobs=20): err= 0: pid=0: Sun Aug 27 08:52:51 2023
read: IOPS=309k, BW=1207Mi (1266M)(354GiB/300027msec)
slat (nsec): min=1250, max=26964k, avg=252003.33, stdev=680956.70
clat (usec): min=1145, max=270577, avg=32912.52, stdev=11049.06
lat (usec): min=1171, max=270627, avg=33165.30, stdev=11103.14匹配lat后的括号内的值和avg后面的值
grep -oP 'lat \([^)]+\): min=[0-9]+, max=[0-9]+, avg=[0-9.]+, stdev=[0-9.]+' /data/fio-a.log | awk -F'[:,=]' '{print $2, $8}'这个命令使用 -oP 参数来进行匹配,并使用 Perl 兼容的正则表达式 (PCRE)。正则表达式 'lat \([^)]+\): min=[0-9]+, max=[0-9]+, avg=[0-9.]+, stdev=[0-9.]+' 匹配 "lat" 后面括号内的任意字符,并捕获 "avg" 后面的数字部分。
然后,通过管道将输出传递给 awk 命令。awk -F'[:,=]' '{print $2, $8}' 使用冒号、逗号和等号作为字段分隔符,然后打印第二个和第八个字段,即 "lat" 后面括号内的内容和 "avg" 后面的数据。
接着我们在试着提取read: IOPS=309k, BW=1207Mi (1266M)(354GiB/300027msec)" 这一行数据的iops后的值和BW后的值
如何使用awk来完成呢?
输出匹配到的最后两行数据
可以使用tail -n 2
变相的,如果提取倒数第二行呢
xxx | tail -n 2 | head -n 1把外界的变量传入到awk中
使用awk -v这种方式
要将外部变量传递给 awk 命令,并在其中进行计算,您可以使用 awk 的 -v 参数。
以下是一个示例,演示如何将外部变量传递给 awk 并进行计算:
result_tib=0.02795
result_gb=$(awk -v result_tib="$result_tib" 'BEGIN{ printf "%.2f", result_tib * 1024 }')
result_mb=$(awk -v result_gb="$result_gb" 'BEGIN{ printf "%.2f", result_gb * 1000 }')
echo "Result in GB: $result_gb GB"
echo "Result in MB: $result_mb MB"在上述示例中,我们使用 -v 参数将外部变量 result_tib 传递给 awk。然后,在 awk 的计算中,我们可以使用该变量进行数值计算。
请注意,我们在 awk 的计算中使用了双引号 " ",以便正确地将外部变量的值传递给 awk。
运行上述脚本将输出转换后的结果,单位为 GB 和 MB。
这样,您可以将外部的变量传递给 awk,并在其中进行计算。
提取匹配到的数字
如何使用正则匹配316882.29 这种类型的字符
[0-9]+\.[0-9]+这个正则表达式由两个部分组成:
[0-9]+匹配一个或多个数字。\.匹配小数点(需要使用反斜杠\进行转义)。[0-9]+再次匹配一个或多个数字。
例如:
echo "Some text 316882.29 Another text" | grep -oE '[0-9]+\.[0-9]+'增加难度:
如何用一个正则匹配下面这三种情况316882.29 5163.1k 1787
要使用正则表达式匹配下面这三种情况:316882.29、5163.1k 和 1787,您可以使用以下正则表达式:
bash
复制
[0-9]+(\.[0-9]+)?[kK]?这个正则表达式可以匹配以下模式的字符串:
[0-9]+匹配一个或多个数字。(\.[0-9]+)?匹配小数点和后面的一个或多个数字(可选)。[kK]?匹配可选的大小写字母 "k"。
这样,正则表达式可以匹配 316882.29、5163.1k 和 1787 这三种情况。
以下是一个示例命令,使用 grep 来匹配包含该类型字符串的行:
bash
复制
echo "316882.29 5163.1k 1787" | grep -oE '[0-9]+(\.[0-9]+)?[kK]?'在这个示例中,我们使用 echo 命令将文本字符串传递给 grep 命令。
然后,我们使用正则表达式 [0-9]+(\.[0-9]+)?[kK]? 来匹配符合要求的字符串。
这样,命令将输出匹配到的结果 316882.29、5163.1k 和 1787。
请注意,这个正则表达式假定匹配的字符串中不会包含空格或其他分隔符。如果字符串中包含空格或其他分隔符,可能需要调整正则表达式以适应实际情况。
以什么开头
^xxx
/k的用法
看这样的一个例子
grep -oP 'BW=\K[^, ]+' /data/fio-a.log在正则表达式中,\K被称为零宽度断言(zero-width positive lookbehind)。它用于匹配模式的一部分,但不将其包含在最终的匹配结果中。
在grep -oP 'BW=\K[^, ]+' /data/fio-a.log命令中,\K的作用是在匹配BW=后面的位置,将前面的部分视为零宽度断言,并将其排除在输出结果之外。这意味着只有[^, ]+部分(匹配一个或多个非逗号和非空格字符)将作为输出结果进行打印。
具体来说,该命令将从/data/fio-a.log文件中查找以BW=开头的字符串,并输出BW=后面的非逗号和非空格字符。例如,如果文件中存在以下内容:
Some text BW=123,456 Another text那么命令的输出将是:
123注意,\K本身不会作为匹配结果的一部分输出,它仅在匹配过程中起到断言的作用,影响最终输出结果。
空格
[[:space:]]
如果要表示开头有空格,那么可以如此^[[:space:]]*IOPS
grep '^[[:space:]]*IOPS' /data/fio-a.log | sed -E 's/.*BW=([0-9.]+)MiB\/s.*/\1/g'是否包含某个字段
一个需求:匹配的文本中,是否包含Mi,如果包含,转换成GI,并且把前面的数字进行单位转换成统一的单位
grep -oE 'BW=[^, ]+' "$file_dir" | awk '{
if ($0 ~ /Mi$/) {
sub(/Mi$/, "", $0);
printf("%s%.2fGi\n", $1, $2 / 1024);
}
else {
print;
}
}' | awk 'END{print}'我们使用了两个awk命令。第一个awk命令用于处理单位转换和格式化输出。首先,我们检查输出行是否以 "Mi" 结尾(例如:9077Mi)。如果是,我们使用sub函数删除 "Mi"。然后,使用printf函数将第二个字段除以1024,并以格式化的方式输出为 "xxx.xxGi"。如果不是以 "Mi" 结尾的行,则直接输出。
第二个awk命令仅用于选择最后一行输出,即使用END{print}。
这样,无论输出结果是 "BW=26.1Gi" 还是 "BW=9077Mi",都会将单位统一为 "Gi" 并进行相应的单位换算。
忽略大小写
sed替换文本
Case1:
假设我们有以下文本内容:
Hello, World!要将"Hello"替换为"Greetings",可以使用如下的sed命令:
sed 's/Hello/Greetings/' filename在这个例子中,我们使用了正则表达式模式Hello来匹配文本中的"Hello",并将其替换为"Greetings"。sed命令会对文件进行替换操作,并输出替换后的结果。
sed直接替换原文
看这样一个命令
sed -i "/^numjobs/c numjobs=${numjobs}" fio.conf这是一个使用 sed 命令的示例,用于在文件 fio.conf 中替换以 numjobs 开头的行。
具体解释如下:
sed: 是一个用于文本处理的流编辑器。-i: 是sed命令的选项之一,表示直接在原始文件中进行修改,而不是输出到标准输出。"/^numjobs/c numjobs=${numjobs}": 这是sed命令的操作部分。在这里,/^numjobs/是一个模式匹配,表示匹配以numjobs开头的行。c是sed的编辑命令之一,表示替换(change)。numjobs=${numjobs}是要替换成的内容,${numjobs}是一个变量,表示要替换的值。fio.conf: 是要进行修改的文件名。
因此,该命令的作用是在文件 fio.conf 中查找以 numjobs 开头的行,并将其替换为 numjobs=${numjobs},其中 ${numjobs} 是一个变量,表示要替换的值。
请注意,在执行该命令之前,需要确保变量 numjobs 已经定义并赋值,否则会将 numjobs 替换为一个空字符串。
匹配到的数值进行累加计算,最后除以总数求得平均值
看这样一个命令
cat /output/*-4M-randread.log |grep IOPS | sed 's|.BW=.∗MiB/s.|\1|g' | awk '{sum+=$1} END {print sum/10}'当我们逐个解释这个命令的各个部分时,它的作用会变得更加清晰:
cat /output/*-4M-randread.log:cat命令用于连接文件并输出它们的内容。在这里,/output/*-4M-randread.log是一个通配符表达式,表示匹配/output/目录下以-4M-randread.log结尾的文件,并将它们的内容输出到标准输出。grep IOPS:grep命令用于在文本中搜索匹配指定模式的行。在这里,它用于过滤出包含 "IOPS" 的行。sed 's|.*BW=\(.*\)MiB/s.*|\1|g':sed命令用于流编辑,这里使用了替换操作。s|.*BW=\(.*\)MiB/s.*|\1|g是一个替换表达式,它匹配以 "BW=" 开头,以 "MiB/s" 结尾的字符串,并提取其中的数字部分。\(...\)用于捕获匹配的内容,\1表示替换为捕获的内容。最终,这个表达式将提取出每行中的 "BW" 值。awk '{sum+=$1} END {print sum/10}':awk是一种文本处理工具,它按行读取输入文本,并对每行执行指定的操作。在这里,awk用于计算提取出的 "BW" 值的平均值。{sum+=$1}表示对每行的第一个字段进行累加,END代表处理结束时执行的操作,{print sum/10}打印累加和除以10的结果。
综合起来,这个命令的作用是从指定的日志文件中提取出包含 "IOPS" 的行,然后从这些行中提取出 "BW" 的值,并计算这些值的平均值(除以10)。
grep -oE用法
-oE 选项用于只输出匹配到的部分,并启用扩展正则表达式。
