首页 > 解决方案 > sed:给定带有绝对路径的文件名,仅对文件名进行替换。仅在模式位于文件名开头时工作

问题描述

我正在研究一种 sed 替换模式,该模式将采用具有绝对路径的文件名,然后打印未更改的输入以及修改后的输入(应仅应用于文件名,而不是路径)。保证明确定义某些路径,因此它永远不会被赋予类似“test.c”的东西,在那种情况下它将是“./test.c”。

我有一些正在工作的正则表达式,但只有当要替换的部分位于文件名的开头时。我希望它可以与文件名的任何部分一起使用。

为了澄清,这里是当前行为的摘要。

INPUT           PATTERN              CURRENT OUTPUT       DESIRED BEHAVIOR?

./test.c        p;s;\(.*/\)t;\1###;  ./test.c             Yes
                                     ./###est.c

testdir/test.c  p;s;\(.*/\)tes;\1#;  testdir/test.c       Yes
                                     testdir/#t.c

./test.c        p;s;\(.*/\)est;\1#;  ./test.c             NO
                                     ./test.c             Should be ./t#.c

如您所见,这是我的模式:

p;s;\(.*/\)SubstringToFind;\1SubstringToInsert;

这是我的逻辑:

p打印未修改的行

s替换(是的,我们都知道)

捕获路径:任意数量的字符加上最后的“/”

SubstringToFind:在文件名的某处寻找模式。

\1: 恢复未修改的路径

SubstringToInsert:插入修改后的文件名

我敢肯定,这只需要一点点添加,比如再添加一个“.*”,我尝试在捕获括号之后添加它,但这只是替换了指定的模式以及它之前的所有文件名字符。我确信解决方案正盯着我看,但我没有看到它。比我更熟悉正则表达式的人有什么帮助吗?谢谢!

标签: regexsed

解决方案


你确实很亲近。最后一种情况的模式est在捕获中指定的斜杠之后立即查找,但est不是在斜杠之后立即查找。

你需要:

$ echo ./test.c | sed -e 'p;s;\(.*/[^/]*\)est;\1#;'
./test.c
./t#.c
$

我使用了否定字符类来尽可能多地避免匹配.*,但你也可以使用它(我不确定否定字符类实际上有什么显着的好处)。稍微严格一点的测试:

$ printf '%s\n' ./test.c ./southwest.c ./west-by-southwest.c south/west/southwestern.c |
> sed -e 'p;s;\(.*/[^/]*\)est;\1#;'
./test.c
./t#.c
./southwest.c
./southw#.c
./west-by-southwest.c
./west-by-southw#.c
south/west/southwestern.c
south/west/southw#ern.c
$

推荐阅读