使用sed将子字符串替换为另一个子字符串

时间:2018-11-26 12:09:07

标签: regex sed

看看以下路径:

/iil/some/path/data/file1
iil/some/path/log/file2
/iil/some/path/BinDir1/file3
iil/some/path/BinDir2/file4

我想使用sed来转换每个以/iilill开头的子字符串,直到遇到以下单词之一: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"

但是它不能按预期工作。有什么建议吗?

1 个答案:

答案 0 :(得分:2)

您原来的sed命令存在一些问题:

  • |交替运算符不会在第一组中转义,并且由于模式被解析为BRE POSIX正则表达式而被匹配为文字管道符号
  • 由于尾随)没有逃脱,第一组被破坏了
  • 不使用数字匹配模式,您只量化了rr*匹配0+ r个字母
  • RHS中没有占位符,并且捕获到第2组的单词已删除(尽管您通过转义最后一个/分隔符而破坏了该命令)。

您可以修复自己的命令,例如

echo "/iil/path/data/file1" | \
   sed 's/\(\/\|\)iil.*\(data\|log\|BinDir[0-9]\)/[PATH]\2/'

请参见the demo

但是,您很可能想将匹配到紧跟data的第一个 logBinDir/。因此,由于Perl支持非贪婪量词,因此我建议使用Perl解决方案:

perl -pe 's,^/?iil/(?:.*?/)?(data|log|BinDir\d+),/$1,'

请参见this demo

详细信息

  • ^-字符串/行的开头
  • /?-可选的/
  • iil/-一个iil/子字符串
  • (?:.*?/)?-一个可选的非捕获组,与除换行符以外的任何0+个字符的1个或0个匹配,在后续子模式的第一次出现之前尽可能少地匹配
  • (data|log|BinDir\d+)-第1组:datalogBinDir,后跟1个数字。

替换为/$1,斜杠和第1组的内容。