sed只替换搜索字符串中的匹配部分

6 sed

我有一个包含以下内容的文件:

Lorem ipsum dolem file1.jar.

  • file1.jar(MD5:12345678901234567890123456789012)
  • file2.jar(MD5:09876543210987654321098765432109)
  • file3.jar(MD5:24681357902468135790246813579024)

我想更换第一台MD5.这个sed命令完成了这项工作:

sed "s/file1.*MD5\:\(.*\)/file1.jar \(MD5\: `md5 file1.jar | awk '{print $4}'`\)/"
Run Code Online (Sandbox Code Playgroud)

有没有办法告诉sed只更换匹配的组,而只留下线的其余部分?例如:

sed "s/file1.*MD5\:\(.*\)/`md5 file1.jar | awk '{print $4}'`/"
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 6

您可以使用搜索来指定要匹配的行,然后使用替换中的更简单的正则表达式:

sed "/file1\.jar (MD5: [0-9A-Fa-f]*)/s/(MD5: [^)]*)/(MD5: $(md5 file1.jar | awk '{print $4}'))/"
Run Code Online (Sandbox Code Playgroud)

这使用$(...)符号来运行命令.其中最棘手的部分是序列))/"出现的结尾.第一个右括号是$(...)符号的结尾; 第二个是替换文本中的一个字符.

第一个正则表达式/file1\.jar (MD5: [0-9A-Fa-f]*)/相当精确地指定了要匹配的行.然后,知道它是正确的行,替换中的模式可以更简单:搜索部分只/(MD5: [^)]*)/查找带括号的MD5数据,安全知道即使许多其​​他行包含相同的模式,也只会应用替换到一个理想的线.

我可能倾向于使用:

md5=$(md5 file1.jar | awk '{print $4}')
sed "/file1\.jar (MD5: [0-9A-Fa-f]*)/  s/(MD5: [^)]*)/(MD5: $md5)/"
Run Code Online (Sandbox Code Playgroud)

它澄清了什么是相当大的(并且不涉及SO上的水平滚动条).您可以在线匹配模式中更精确:

md5=$(md5 file1.jar | awk '{print $4}')
sed "/^file1\.jar (MD5: [0-9A-Fa-f]\{32\})\$/  s/(MD5: [^)]*)/(MD5: $md5)/"
Run Code Online (Sandbox Code Playgroud)

这坚持正好32个十六进制数字和行尾的紧密括号.


其中一条评论问:

sed可以以这样的方式操作,即替换字符串只替换搜索模式中的匹配组吗?例如,给定's/A B \(D\)/C/',它输出A B C.

如果我理解(澄清)问题,那么你可以通过适当的捕获来做你想做的事 - 但是替换部分必须准确指定你想要的输出(没有你想要的快捷方式).因此,对于该示例,您可以编写如下内容:

s/\(A B \)\(D\)/\1C/
Run Code Online (Sandbox Code Playgroud)

(捕获\(D\)不需要捕获括号,因为捕获的材料不用于替换,您可以编写以下任一项:

s/\(A B \)D/\1C/
s/\(A B\) D/\1 C/
Run Code Online (Sandbox Code Playgroud)

你也可以这样做:

/A B / s/D/C/
Run Code Online (Sandbox Code Playgroud)

这有一个搜索(对于A B序列),然后替补查找D并替换它C.这基本上是主要答案所暗示的.您也可以这样做:

/\(A B\) D/ s//\1 C/
Run Code Online (Sandbox Code Playgroud)

"空搜索"应该重复匹配,但必须完整地写出替换,这实际上与以前的命令之一相同:

s/\(A B\) D/\1 C/
Run Code Online (Sandbox Code Playgroud)