![如果 n+2 行包含特定字符串,如何替换匹配字符串](https://linux22.com/image/155590/%E5%A6%82%E6%9E%9C%20n%2B2%20%E8%A1%8C%E5%8C%85%E5%90%AB%E7%89%B9%E5%AE%9A%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E5%A6%82%E4%BD%95%E6%9B%BF%E6%8D%A2%E5%8C%B9%E9%85%8D%E5%AD%97%E7%AC%A6%E4%B8%B2.png)
例如:如果 n+2 行(版本行包含 com.icc.id.version),则将 com.icc.id 替换为“abc”。如果是其他东西,请勿更换。这应该适用于文件夹“common”的所有子目录中存在的所有 pom 文件
<groupId>com.icc.id</groupId>
<artifactId>abc</artifactId>
<version>${project.version}</version>
<groupId>com.icc.id</groupId>
<artifactId>ifd</artifactId>
<version>${com.icc.id.version}</version>
答案1
这超出了您的需要,但它可以帮助您在将来对您的记录做更多的事情:
$ cat tst.awk
BEGIN { numLines = 3 }
{
lineNr = (NR - 1) % numLines + 1
rec[lineNr] = $0
}
lineNr == numLines {
if ( rec[3] ~ /com\.icc\.id\.version/ ) {
sub(/com\.icc\.id/,"abc",rec[1])
}
for (lineNr=1; lineNr<=numLines; lineNr++) {
print rec[lineNr]
}
delete rec
}
$ awk -f tst.awk file
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version)
要对所有子目录中的所有“.pom”文件执行此操作,假设“pom 文件”具有这样的扩展名并使用 GNU awk for -i inplace
:
find . -name '*.pom' -exec awk -i inplace -f tst.awk {} +
答案2
当第 n 行匹配时,将第 n 行和第 n+1 行存储在保留状态。读取第n+2个并检查其是否有规定的内容。比赛结束后,召回保持并替换为 abc。
$ sed -ne '
/>com\.icc\.id</!bp
N;h;n
/\<com\.icc\.id\.version\>/{
x;s/>com\.icc\.id<\(.*\n\)/>abc<\1/;x
}
x;G;:p;p
' inp.pom
答案3
如果您的文件足够小以适合内存,您可以执行以下操作:
$ awk '{lines[NR]=$0}END{for(i in lines){ if(lines[i] ~ /com\.icc\.id/ && lines[i+2] ~ /com\.icc\.id\.version/){gsub("com\\.icc\\.id","abc",lines[i])} print lines[i]}}' file
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version)
或者,更易读一点:
$ awk '{
lines[NR]=$0
}
END{
for(i in lines){
if(lines[i] ~ /com\.icc\.id/ &&
lines[i+2] ~ /com\.icc\.id\.version/){
gsub(/com\.icc\.id/,"abc",lines[i])
}
print lines[i]
}
}' file
(groupId)com.icc.id(/groupId)
(artifactId)abc(/artifactId)
(version)${project.version}(/version)
(groupId)abc(/groupId)
(artifactId)ifd(/artifactId)
(version)${com.icc.id.version}(/version)
要将其应用于.pom
目录和任何子目录中具有扩展名的所有文件(我假设这就是“pom 文件”的意思)common
,您可以执行以下操作(假设您正在使用bash
, 和 GNU gawk
):
shopt -s globstar
tmpFile=$(mktemp)
for file in common/**/*.pom; do
awk '{
lines[NR]=$0
}
END{
for(i in lines){
if(lines[i] ~ /com\.icc\.id/ &&
lines[i+2] ~ /com\.icc\.id\.version/){
gsub(/com\.icc\.id/,"abc",lines[i])
}
print lines[i]
}
}' "$file" > "$tmpFile" && mv "$tmpFile" "$file"
done
答案4
使用原始xml
示例(标签需要首先修复,因为dependencies
未关闭)并使用xmlstarlet
xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId" -v "BANANA" data.xml
编辑
groupId
考虑到仅对version
包含com.icc.version
和groupId
不包含的位置进行更改的双重约束,com.icc.id
则以下内容应仅选择和替换这些节点
xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId[not(contains(text(), 'com.icc.id'))]" -v 'BANANA' data.xml
或者如果节点的整个文本groupID
是com.icc.id
xmlstarlet ed -N "x=http://maven.apache.org/POM/4.0.0" -u "//x:dependency[x:version[contains(text(), 'com.icc.version')]]/x:groupId[text() !='com.icc.id']" -v 'BANANA' data.xml
@terdon 的循环globstar
将找到文件,并且输出将stdout
供您检查。要使更改永久保留在文件中,请在命令中.pom
包含该选项。-L
xmlstarlet ed -L -N etc.....
输入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.icc.id</groupId>
<artifactId>solution-commons</artifactId>
<version>${com.icc.id.version}</version>
</dependency>
<dependency>
<groupId>com.icc.banana</groupId>
<artifactId>application-common</artifactId>
<version>${com.icc.version}</version>
</dependency>
<dependency>
<groupId>com.icc.id</groupId>
<artifactId>application-common</artifactId>
<version>${com.icc.banana}</version>
</dependency>
</dependencies>
</project>
输出
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.icc.id</groupId>
<artifactId>solution-commons</artifactId>
<version>${com.icc.id.version}</version>
</dependency>
<dependency>
<groupId>BANANA</groupId>
<artifactId>application-common</artifactId>
<version>${com.icc.version}</version>
</dependency>
<dependency>
<groupId>com.icc.id</groupId>
<artifactId>application-common</artifactId>
<version>${com.icc.banana}</version>
</dependency>
</dependencies>
</project>
一警告关于这一点。xmlstarlet
依赖于了解namespace
,因此如果namespace
所有文件中的 都相同,则没有问题。如果不同,那么您将需要询问每个文件并确定namespace
并将其作为变量传递。
ns=$(grep -Po "(?<=xmlns=\")[^\"]*" data.xml)