我需要这个awk命令来替换ss:Width =" 252"在文本的第一个XML标签中使用ss:Width =" 140"并留下剩下的标签:
cat <<- EOF > text
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="189"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="189"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
EOF
awk '{c=++count[$0]} c==1 {sub(/ss:Width=\"[0-9]{1,4}\"/,"ss:Width=\"140\"")} {print}' text > newf
cat newf
相反,它取代了三个唯一匹配中每个匹配项的第一个实例中的表达式(三个完全替换,而我只想要一个。)
<ss:Column ss:AutoFitWidth="1" ss:Width="140"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="140"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="140"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="189"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
为什么它会这样?增量器在我的awk命令中如何表现?我希望它在/ss:Width=\".*\" /的第一次合格比赛后增加,但看起来它没有递增直到所有唯一找到匹配项,然后忽略后续的非唯一匹配项。是对的吗?我试图强制计数器在c == 1块的末尾递增,如下所示:
awk '{c=++count[$0]} c==1 {sub(/ss:Width=\".*\"/,"ss:Width=\"140\"");c++} {print}' text > newf
但我得到了相同的输出。我在sed&amp; amp;尝试这项任务时没有运气。我还是宁愿用awk做这件事。我对理解这种awk语法特别感兴趣。
编辑:我通过将其中一个宽度属性更改为另一个随机数来测试此理论。它也用140替换那个。因此,它限制了所有匹配表达式的第一个实例,而不是第一个匹配表达式本身。
编辑:正如科迪指出我的正则表达式是贪婪的。我改变了。*为[0-9] {1,4}然而行为是相同的 - 它仍然只替换每个唯一匹配的第一个实例。我还改变了一个XML标签&#39; width属性为第3个唯一编号,并更新输出以说明我尝试修复的行为。
这是AIX / ksh。
答案 0 :(得分:2)
awk 'found == 0 { found = sub(/ss:Width=\"[0-9]{1,4}\"/,"ss:Width=\"140\"")} //' text > newf
你可以缩短一点。
您的旧方法是保留一系列由输入行索引的计数器。这就是为什么它展示了你并不期望的行为。
其他一些答案假设所有行都匹配/ss:Width/
正则表达式和/或总是在一行的末尾找到width属性。在你的情况下可能是真的,但值得注意。我决定不在上面的脚本中假设这些东西。
答案 1 :(得分:2)
看起来你的正则表达式是贪婪的。
sub(regexp,replacement [,target]) 子函数改变目标的值。它会搜索此值,该值被视为字符串,用于正常表达式正则表达式匹配的最左边,最长的子字符串。
答案 2 :(得分:2)
试试这个:
awk '($0 ~ /ss:Width/) {if (once != 1) {sub("[0-9]+\"/>","140\"/>")}; once=1; print}' text
它会查找包含ss:Width
的第一行,然后使用140
替换结束标记之前的最后一个数字。
答案 3 :(得分:1)
使用自定义字段分隔符实际上非常简单:
awk -F ' ss:Width="252"' -v r=' ss:Width="140"' '!p && NF>1{p=1; $1 = $1 r} 1' text
<ss:Column ss:AutoFitWidth="1" ss:Width="140"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="189"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="189"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="126"/>
<ss:Column ss:AutoFitWidth="1" ss:Width="252"/>
-F ' ss:Width="252"'
将字段分隔符设置为ss:Width="252"
。
!p && NF>1
为搜索文本的第一个实例添加了替换值r
。