我只想得到一个可能是也可能不是gzip的文件号。但是,sed中的正则表达式似乎不支持?
。这是我尝试过的:
echo 'file_1.gz'|sed -n 's/.*_\(.*\)\(\.gz\)?/\1/p'
却什么也没有返回。然后,我向正在分析的字符串添加了一个?
:
echo 'file_1.gz?'|sed -n 's/.*_\(.*\)\(\.gz\)?/\1/p'
并得到了:
1
所以,看起来在大多数正则表达式中使用的?
在sed中不受支持,对吧?那么,我只想让sed为file_1
和file_1.gz
提供一个1
。如果执行时间很关键,那么在bash脚本中实现这一点的最佳方法是什么?
发布于 2010-12-04 01:34:55
与x?
等效的是\(x\|\)
。
但是,许多版本的sed支持启用“扩展正则表达式”的选项,其中包括?
。在GNU中,这个标志是-r
。请注意,这也会将未转义的括号更改为进行分组。例如:
echo 'file_1.gz'|sed -n -r 's/.*_(.*)(\.gz)?/\1/p'
实际上,在您的正则表达式中有另一个bug,那就是如果有".gz“的话,括号中贪婪的.*
将会吞噬掉它。据我所知,sed没有一个非贪婪的等价物*
,但是你可以使用|
来解决这个问题。sed (和许多其他正则表达式实现)中的|
将使用最左边的匹配,所以您可以这样做:
echo 'file_1.gz'|sed -r 's/(.*_(.*)\.gz)|(.*_(.*))/\2\4/'
这会尝试与.gz匹配,并且只有在没有它的情况下才会尝试,如果不起作用。实际上,组2或组4中只有一个会存在(因为它们位于同一|
的两端),所以我们只需将它们连接起来就可以得到我们想要的值。
发布于 2013-03-15 07:57:02
如果您正在寻找问题中给出的特定示例的答案,或者为什么它不正确地使用?
(不管语法如何),请参阅the answer by Laurence Gonsalves。
如果您正在寻找通用问题的答案,即为什么?
没有像您预期的那样在sed中显示其特殊含义:
默认情况下,sed使用“POSIX basic正则表达式语法”,因此必须将问号转义为\?
以应用其特殊含义,否则它将匹配文字问号。作为另一种选择,您可以使用-r
或--regexp-extended
选项来使用“扩展正则表达式语法”,它颠倒了转义和非转义特殊字符(包括?
)的含义。
用GNU sed文档的话说(在Linux上运行'info sed‘查看):
基本正则表达式和扩展正则表达式之间的唯一区别是几个字符的行为:'?‘、'+’、圆括号和花括号('{}')。如果您希望它们表现为特殊字符,则基本正则表达式需要对它们进行转义,而在使用扩展正则表达式时,如果希望它们与文字字符匹配,则必须对它们进行转义。
并解释了该选项:
-r
--regexp-extended
使用扩展正则表达式,而不是基本正则表达式。扩展正则表达式是‘`egrep’接受的那些;它们可以更清晰,因为它们通常具有较少的反斜杠,但它们是GNU扩展,因此使用它们的脚本不可移植。
更新
较新版本的GNU sed现在这样说:
-E
-r
--regexp-extended
使用扩展正则表达式,而不是基本正则表达式。扩展正则表达式是'egrep‘接受的正则表达式;它们可以更清晰,因为它们通常具有较少的反斜杠。从历史上看,这是一个GNU扩展,但是'-E‘扩展名后来被添加到POSIX标准(http://austingroupbugs.net/view.php?id=528)中,因此使用'-E’表示可移植性。GNU sed多年来一直接受'-E‘作为未记录的选项,*BSD sed也接受'-E’已有多年,但使用'-E‘的脚本可能无法移植到其他较旧的系统。
因此,如果您需要保持与古老的GNU sed的兼容性,请坚持使用-r
。但是,如果您希望在更现代的系统上获得更好的跨平台可移植性(例如,Linux+Mac支持),请使用-E
(但请注意,GNU sed和BSD sed之间仍然存在一些怪癖和差异,因此您必须确保您的脚本在任何情况下都是可移植的)。
发布于 2010-12-04 01:34:36
echo 'file_1.gz'|sed -n 's/.*_\(.*\)\?\(\.gz\)/\1/p'
很管用。你必须将返回值放在正确的位置,并且必须避开它。
https://stackoverflow.com/questions/4348166
复制相似问题