考虑这个命令:
echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)/\1\n\2/'
(将直到最后一个字符的任意字符匹配到第一个捕获组,.
并将其后的任何字符匹配到第二个捕获组。)
输出:
string.with
dots
合理地(我认为)我认为使用正确组合的锚点可以扭转这种行为(即匹配将string
针对第一个捕获组和with.dots
第二个捕获组),但是:
echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)/\1\n\2/'
echo "string.with.dots" | sed 's/^\(.*\)\.\(.*\)$/\1\n\2/'
echo "string.with.dots" | sed 's/\(.*\)\.\(.*\)$/\1\n\2/'
全部输出:
string.with
dots
我不知道模式匹配是如何实现的,但似乎它总是优先考虑更靠近字符串开头的模式,而不是更靠近字符串结尾的模式(尽管存在^
或缺失$
)。
怎么能这种行为如果可能的话,进行更改(即,不是如何为这个例子编写一个硬编码的解决方案,而是如何将模式匹配的优先级顺序反转为sed
或反转为正则表达式)?
答案1
添加两个rev
并交换\1
和\2
:
echo "string.with.dots" | rev | sed 's/\(.*\)\.\(.*\)/\2\n\1/' | rev
输出:
细绳 带点
答案2
为了得到你想要的,尝试这个:
sed -r 's/^([^.]*)\.(.*)/\1\n\2/'
测试:
$ echo "string.with.dots" | sed -r 's/^([^.]*)\.(.*)/\1\n\2/'
string
with.dots
sed
将会贪婪地匹配,因此当您使用sed 's/\(.*\)\.\(.*\)/\1\n\2/'
它时,它将贪婪地匹配到最后一个.
作为第一个捕获的组,然后将其余的.
作为第二个。
在我的sed
表达中,为了避免sed
贪婪,我必须寻找一些替代方案。我从头到尾匹配 a.
作为第一组 ( [^.]*
),然后将第一组匹配之后的任何内容作为第二组。
现在,如果您希望所有部分都放在.
单独的行中:
$ echo "string.with.dots" | sed -r 's/^([^.]*)\.([^.]*)\.(.*)/\1\n\2\n\3/'
string
with
dots
答案3
我想知道你是否可以使用 bash参数扩展
$ s="string.with.dots"
$ echo "${s%%.*}"; echo "${s#*.}"
string
with.dots
$ echo "${s%.*}"; echo "${s##*.}"
string.with
dots