我正在使用正则表达式练习sed命令,但结果并不像预期的那样。我在mac Sierra上使用终端。 这是输入数据:
Mark watermellons 12
Robert pears 4
Terry oranges 9
Lisa peaches 7
Susy oranges 12
Mark grapes 39
Anne mangoes 7
Greg pineapples 3
Oliver rockmellons 2
Betty limes 14
我正在尝试交换第一列和第二列。我用了这个命令:
sed 's/\(.+\) \(.+\) /\2 \1/ ' file.txt
此命令返回相同的输入。但是当我使用时,
sed 's/\(.*\) \(.*\) /\2 \1 /' file.txt
列正在交换。为什么“+”不匹配,因为每行至少有一个字符。
另外, 当我使用
sed 's/\(.*\) \(.*\)/\2 \1 /' file.txt
第一个括号是捕获前两列,第二个是最后一列,为什么第一个括号没有捕获第一列?
答案 0 :(得分:8)
问题不在于你对正则表达式和贪婪匹配等的理解。问题很简单,问题中的示例用法中没有实现+
。
在sed
,默认情况下,+
并不代表"前一个符号中的一个或多个"正如你可能已经习惯了其他正则表达式语法。
要使其在BSD sed
中工作(就像在OSX上一样),
你需要使用-E
启用扩展正则表达式,
并且还更改捕获组语法:
sed -E 's/(.+) (.+) /\2 \1/ ' file.txt
另请注意,+
基本上只是一个捷径,
所以你总是可以用老式的方式写出来:
sed 's/\(..*\) \(..*\) /\2 \1/' file.txt
顺便说一句,请注意BSD sed
和GNU sed
之间的区别。
例如,这在GNU sed
中按预期工作,但在BSD sed
中没有:
sed 's/\(.\+\) \(.\+\) /\2 \1/ ' file.txt
本文中的前两个解决方案在GNU和BSD sed
中都有效。
只要有可能,选择适用于两者的语法都是件好事,
防止各种调试地狱。
答案 1 :(得分:3)
Casimir et Hippolyte在评论中指出,+
在sed中不可用。
s/\(.*\) \(.*\) /\2 \1 /
说“匹配0个或多个字符后跟一个空格,后跟0个或更多个字符,后跟一个空格。所以要匹配,输入字符串必须至少有2个空白字符,任意数量的其他字符,但必须至少有2个空格。
s/\(.*\) \(.*\)/\2 \1 /
说“匹配0个或多个字符后跟一个空格,后跟0个或更多字符。所以要匹配,输入字符串必须至少1个空格和任意数字其他字符。由于.*
是贪婪的,它匹配第一列,第一个空格和第二列,然后模式的空格部分与输入的第二个空格匹配,最后.*
评估为0个字符。