如何让sed仅影响第一个匹配的范围

huangapple go评论55阅读模式
英文:

how to get sed affect only the first matched range

问题

这是您要翻译的内容:

我正在使用这个sed命令

sed -i "/^### Header$/,/^### [^#]*$/{//!d}"

这个sed命令会删除从Header到Header 2之间的所有文本。
我只想删除第一个匹配范围内的文本。

请注意,我不知道下一个Header的标题是什么!

输入:

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 


输出:

### Header
### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

如果您需要进一步的帮助,请随时提出。

英文:

I am using this sed

sed -i "/^### Header$/,/^### [^#]*$/{//!d}"

This sed deleted all the text between Header to Header 2.
I want only to delete the text for the first matched range.

Note I don't know what is the title of the next Header!

Input:

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

output:

### Header
### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

### Header

blabla

### Header 2 

some text 

答案1

得分: 3

使用 GNU `sed`

$ sed '/^### Header$/,/^###/{1,/^###/{//!d}}' input_file

Header 2

some text

Header

blabla

Header 2

some text

Header

blabla

Header 2

some text


<details>
<summary>英文:</summary>

Using GNU `sed`

$ sed '/^### Header$/,/^###/{1,/^###/{//!d}}' input_file

Header

Header 2

some text

Header

blabla

Header 2

some text

Header

blabla

Header 2

some text


</details>



# 答案2
**得分**: 0

sed 是在简单字符串上进行 s/old/new/ 替换的优秀工具,对于其他情况,只需使用 awk 来结合清晰度、可移植性、健壮性、效率等方面。在这种情况下,在任何 Unix 系统上的任何 shell 中使用任何 awk:

$ awk '/^### [^#]/{inRange=0} !inRange{print} /^### Header$/ && (++cnt==1){inRange=1}' file

Header

Header 2

一些文本

Header

blabla

Header 2

一些文本

Header

blabla

Header 2

一些文本


请注意,通过使用一个标志变量 `inRange`,你无需测试范围的开始或结束两次,这在使用范围运算符时很常见,参见 https://stackoverflow.com/questions/23934486/is-a-start-end-range-expression-ever-useful-in-awk。通过使用计数器变量 `cnt`,你可以轻松修改代码,使其操作于范围的第二个、第十个或其他任何出现,而不仅仅是第一次出现。sed 没有变量。

<details>
<summary>英文:</summary>

sed is an excellent tool for doing s/old/new/ on simple strings, for anything else just use awk for some combination of clarity, portability, robustness, efficiency, etc. In this case, using any awk in any shell on every Unix box:

    $ awk &#39;/^### [^#]/{inRange=0} !inRange{print} /^### Header$/ &amp;&amp; (++cnt==1){inRange=1}&#39; file
    ### Header
    ### Header 2
    
    some text
    
    ### Header
    
    blabla
    
    ### Header 2
    
    some text
    
    ### Header
    
    blabla
    
    ### Header 2
    
    some text

Note that by using a flag variable `inRange` you don&#39;t have to test the start or end of the range twice as is common if you use a range operator, see https://stackoverflow.com/questions/23934486/is-a-start-end-range-expression-ever-useful-in-awk, and by using a counter variable `cnt` you could trivially change the code to operate on the 2nd or 10th or any other occurrence of the range instead of or in addition to the first occurrence. sed doesn&#39;t have variables.

</details>



huangapple
  • 本文由 发表于 2023年5月22日 15:21:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76303820.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定