看看以下路径:
/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"
但它没有按预期工作。有什么建议吗?
最佳答案
您原来的 sed
命令存在一些问题:
|
交替运算符在第一组中不会转义,并且会作为文字管道符号进行匹配,因为该模式被解析为 BRE POSIX 正则表达式- 第一组已损坏,因为尾随
)
未转义 - 未使用数字匹配模式,您只是量化了
r
,r*
匹配 0+r
个字母 - RHS 中没有占位符,并且捕获到第 2 组的单词将被删除(尽管您通过转义最后一个
/
分隔符破坏了该命令)。
你可以修复你自己的命令,例如
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 组的内容。
关于regex - 使用 sed 将一个子字符串替换为另一个子字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53480823/