我正在使用GNU bash 4.3.48
我本以为
echo "23S62M1I19M2D" | sed 's/.*\([0-9]*M\).*/\1/g'
将输出62M19M.但事实并非如此。
sed 's/\([0-9]*M\)//g'
删除所有[0-9]*M
并检索23S1I2D。但\1
小组并没有像我想象的那样工作。
sed 's/.*\([0-9]*M\).*/ \1 /g'
检索M.
我做错了什么?
谢谢!
发布于 2021-11-03 18:14:53
问题是.*
是贪婪的。由于只有M
是必需的,所以当引擎找到最后一个M
时,它满足正则表达式,所以所有字符串都匹配,因此在用\1
反向引用替换之后,捕获并保存了M
。
这意味着,使用sed
很难做到这一点。使用Perl可以更容易地做到这一点,因为它支持匹配和跳过模式:
#!/bin/bash
perl -pe 's/\d+M(*SKIP)(*F)|.//g' <<< "23S62M1I19M2D"
见在线演示。模式匹配
\d+M(*SKIP)(*F)
-一个或多个数字,M
,然后省略匹配,然后从失败位置搜索下一个匹配。|.
-或匹配除换行字符以外的任何字符。或者简单地匹配所有的事件并将它们连接起来:
perl -lane 'BEGIN{$a="";} while (/\d+M/g) {$a .= $&} END{print $a;}' <<< "23S62M1I19M2D"
所有\d+M
匹配都附加到$a
变量,该变量在处理字符串结束时打印。
发布于 2021-11-03 19:22:49
使用显示的示例和awk
,您可以尝试执行以下程序。
echo "23S62M1I19M2D" |
awk '
{
val=""
while(match($0,/[0-9]+M/)){
val=val substr($0,RSTART,RLENGTH)
$0=substr($0,RSTART+RLENGTH)
}
print val
}
'
解释:的简单解释将是,使用echo
打印值并将其作为标准输入发送到awk
程序。在awk
程序中,使用它的match
函数来匹配它(/[0-9]+M
)中提到的正则表达式,运行循环查找每一行中的所有匹配值,并在每一行的最后打印所收集的匹配值。
发布于 2021-11-03 19:26:54
这可能对您有用(GNU sed):
sed -nE '/[0-9]*M/{s//\n&\n/g;s/(^|\n)[^\n]*\n?//gp}' file
用换行符包围匹配,然后删除不匹配的部分。
备选办法,使用grep和tr:
grep -o '[0-9]*M' file | tr -d '\n'
注意:tr
删除所有换行符(包括最后一行)以恢复最后一个换行符,请使用:
grep -o '[0-9]*M' file | tr -d '\n' | paste
替代解决方案将将所有结果连接到一行中。要实现第一个解决方案的相同结果,请使用:
sed -nE '/[0-9]*M/{s//\n&\n/g;s/(^|\n)[^\n]*\n?//g;H};${x;s/\n//gp}' file
https://stackoverflow.com/questions/69829591
复制相似问题