bash Sed 在第二次出现时替换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46238843/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 16:27:30  来源:igfitidea点击:

Sed replace at second occurrence

regexbashsednon-greedy

提问by BeGreen

I want to remove a pattern with sed, only at second occurence. Here is what I want, remove a pattern but on second occurrence.

我想使用 sed 删除模式,仅在第二次出现时。这是我想要的,删除一个模式,但在第二次出现时。

What's in the file.csv:

file.csv 中的内容:

a,Name(null)abc.csv,c,d,Name(null)abc.csv,f
a,Name(null)acb.csv,c,d,Name(null)acb.csv,f
a,Name(null)cba.csv,c,d,Name(null)cba.csv,f

Output wanted:

想要的输出:

a,Name(null)abc.csv,c,d,Name,f
a,Name(null)acb.csv,c,d,Name,f
a,Name(null)cba.csv,c,d,Name,f

This is what i tried:

这是我试过的:

sed -r 's/(\(null)\).*csv//' file.csv

The problem here is that the regex is too greedy, but i cannot make is stop. I also tried this, to skip the first occurrence of "null":

这里的问题是正则表达式太贪婪了,但我不能停止。我也试过这个,跳过第一次出现的“null”:

sed -r '0,/null/! s/(\(null)\).*csv//' file.csv

Also tried but the greedy regex is still the problem.

也尝试过,但贪婪的正则表达式仍然是问题。

sed -r 's/(\(null)\).*csv//2' file.csv

I've read that ?can make the regex "lazy", but I cannot make it workout.

我读过?可以使正则表达式“懒惰”,但我不能让它锻炼。

sed -r 's/(\(null)\).*?csv//' file.csv

采纳答案by RomanPerekhrest

The more robust awksolution:

更强大的awk解决方案:

Extended sample file input.csv:

扩展示例文件input.csv

12,Name(null)randomstuff.csv,2,3,Name(null)randomstuff.csv, false,Name(null)randomstuff.csv
12,Name(null)AotherRandomStuff.csv,2,3,Name(null)AotherRandomStuff.csv, false,Name(null)randomstuff.csv
12,Name(null)alphaNumRandom.csv,2,3,Name(null)alphaNumRandom.csv, false,Name(null)randomstuff.csv


The job:

工作:

awk -F, '{ c=0; for(i=1;i<=NF;i++) if($i~/\(null\)/ && c++==1) sub(/\(null\).*/,"",$i) }1' OFS=',' input.csv

The output:

输出:

12,Name(null)randomstuff.csv,2,3,Name, false,Name(null)randomstuff.csv
12,Name(null)AotherRandomStuff.csv,2,3,Name, false,Name(null)randomstuff.csv
12,Name(null)alphaNumRandom.csv,2,3,Name, false,Name(null)randomstuff.csv

回答by Sundeep

seddoes provide an easy way to specify which match to be replaced. Just add the number after delimiters

sed确实提供了一种简单的方法来指定要替换的匹配项。只需在分隔符后添加数字

$ sed 's/(null)[^.]*\.csv//2' ip.csv
a,Name(null)abc.csv,c,d,Name,f
a,Name(null)acb.csv,c,d,Name,f
a,Name(null)cba.csv,c,d,Name,f

$ # or [^,] if there are no , within fields
$ sed 's/(null)[^,]*//2' ip.csv
a,Name(null)abc.csv,c,d,Name,f
a,Name(null)acb.csv,c,d,Name,f
a,Name(null)cba.csv,c,d,Name,f

Also, no need to escape ()when not using extended regular expressions

此外,()不使用扩展正则表达式时无需转义

回答by Claes Wikner

Execute:

执行:

awk '{sub(/.null.....csv,f/,",f")}1' file

And the output should be:

输出应该是:

a,Name(null)abc.csv,c,d,Name,f
a,Name(null)acb.csv,c,d,Name,f
a,Name(null)cba.csv,c,d,Name,f