我只是想得到一个可能是也可能不是gzip的文件的编号.但是,似乎sed中的正则表达式不支持a ?.这是我试过的:
echo 'file_1.gz'|sed -n 's/.*_\(.*\)\(\.gz\)?/\1/p'
没有任何回报.然后我?在正在分析的字符串中添加了一个:
echo 'file_1.gz?'|sed -n 's/.*_\(.*\)\(\.gz\)?/\1/p'
得到了:
1
因此,看起来?sed中不支持大多数正则表达式中使用的,对吧?那么,我想要sed给一个1for file_1和file_1.gz.如果执行时间至关重要,那么在bash脚本中执行此操作的最佳方法是什么?
Lau*_*ves 35
相当于x?是\(x\|\).
但是,许多版本的sed都支持启用"扩展正则表达式"的选项,其中包括?.在GNU sed中,标志是-r.请注意,这也会改变未转义的parens进行分组.例如:
echo 'file_1.gz'|sed -n -r 's/.*_(.*)(\.gz)?/\1/p'
Run Code Online (Sandbox Code Playgroud)
实际上,你的正则表达式中还有另一个错误,那就是如果有的话.*,parens 中的贪婪会吞噬".gz".*据我所知,sed没有非贪婪的等价物,但你可以|用来解决这个问题.|在sed(以及许多其他正则表达式实现)中将使用最左边的匹配,因此您可以执行以下操作:
echo 'file_1.gz'|sed -r 's/(.*_(.*)\.gz)|(.*_(.*))/\2\4/'
Run Code Online (Sandbox Code Playgroud)
这会尝试与.gz匹配,只有在没有它的情况下才会尝试.实际上只存在组2或组4中的一个(因为它们位于相同的两侧|)所以我们只是将它们连接起来以获得我们想要的值.
如果您正在寻找问题中给出的具体示例的答案,或者为什么它使用?不正确(无论语法如何),请参阅Laurence Gonsalves的答案.
如果你正在寻找一般问题的答案,为什么?它没有像你期望的那样在sed中表现出它的特殊含义:
默认情况下,sed使用"POSIX基本正则表达式语法",因此必须对问号进行转义\?以应用其特殊含义,否则它将与文字问号匹配.作为替代方案,您可以使用-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 seds也接受'-E'多年,但使用'-E'的脚本可能不会移植到其他旧系统.
所以,如果你需要保持与古代GNU sed的兼容性,坚持下去-r.但如果您希望在更现代的系统上更好的跨平台可移植性(例如Linux + Mac支持),那么请-E注意(但请注意,GNU sed和BSD sed之间仍存在一些怪癖和差异,因此您必须确保脚本在任何情况下都是可移植的).