看看以下路径:
/iil/some/path/data/file1
iil/some/path/log/file2
/iil/some/path/BinDir1/file3
iil/some/path/BinDir2/file4
我想使用sed
来转换每个以/iil
或ill
开头的子字符串,直到遇到以下单词之一:data,log,BinDir*
。因此输出将是:
[PATH]/data/file1
[PATH]/log/file2
[PATH]/BinDir1//file3
[PATH]/BinDir2/file4
我尝试过的事情:
echo "/iil/path/data/file1" | /usr/bin/sed "s/\(\/|)iil.*\(data\|log\|BinDir*\)/[PATH]\/g"
但是它不能按预期工作。有什么建议吗?
答案 0 :(得分:2)
您原来的sed
命令存在一些问题:
|
交替运算符不会在第一组中转义,并且由于模式被解析为BRE POSIX正则表达式而被匹配为文字管道符号)
没有逃脱,第一组被破坏了r
,r*
匹配0+ r
个字母/
分隔符而破坏了该命令)。您可以修复自己的命令,例如
echo "/iil/path/data/file1" | \
sed 's/\(\/\|\)iil.*\(data\|log\|BinDir[0-9]\)/[PATH]\2/'
请参见the demo
但是,您很可能想将匹配到紧跟data
的第一个 log
,BinDir
和/
。因此,由于Perl支持非贪婪量词,因此我建议使用Perl解决方案:
perl -pe 's,^/?iil/(?:.*?/)?(data|log|BinDir\d+),/$1,'
请参见this demo。
详细信息
^
-字符串/行的开头/?
-可选的/
iil/
-一个iil/
子字符串(?:.*?/)?
-一个可选的非捕获组,与除换行符以外的任何0+个字符的1个或0个匹配,在后续子模式的第一次出现之前尽可能少地匹配(data|log|BinDir\d+)
-第1组:data
或log
或BinDir
,后跟1个数字。替换为/$1
,斜杠和第1组的内容。