简体   繁体   English

Bash:替换特定列中的模式,但仅限于两个模式之间的行

[英]Bash: replacing pattern in specific column but only in lines between two patterns

I have files with this kind of structure: 我有这种结构的文件:

abc
def
ghi
...
x x y x x
x x z x x
x x y x x
...
JKL
x x y x x
x x z x x
x x y x x
...
...
*empty line*
mno
pqr
...
...

I would like to copy the whole file to a new file but with some changes. 我想将整个文件复制到一个新文件,但有一些更改。 Fist, I want to affect only the lines between pattern JKL and the next empty line. 拳头,我想只影响模式JKL和下一个空行之间的线。 On top of that, I need to replace every occurrence of the pattern y with a new pattern NEW, but only if it appears in the third column. 最重要的是,我需要用新模式NEW替换模式y的每个匹配项,但前提是它出现在第三列中。

I tried using sed, but I got stuck at how to select columns: 我尝试使用sed,但我不知道如何选择列:

sed -ne '/JKL/,/^$/s/y/NEW/'

this, of course, replaced y with NEW in all columns. 当然,这在所有列中都用NEW替换了y。

I also tried looking up awk, but I could only find examples of the two separate needs I have, and wasn't able to put them together. 我也试过查找awk,但我只能找到我所拥有的两个独立需求的例子,并且无法将它们组合在一起。 How could I do it? 我怎么能这样做?

Third column is something that follows the beginning of a line, a sequence of non-spaces, a spaces, another sequence of non-spaces, and finally a space: 第三列是一行,它跟在行的开头,一系列非空格,一个空格,另一个非空格序列,最后是一个空格:

sed '/^JKL$/,/^$/s/^\([^ ][^ ]* [^ ][^ ]*\) y /\1 NEW /'

or, if your sed supports -r or -E : 或者,如果你的sed支持-r-E

sed -E '/^JKL$/,/^$/s/^([^ ]+ [^ ]+) y /\1 NEW /' 

awk also allows the range syntax similar to sed , see How to select lines between two patterns? awk还允许范围语法类似于sed ,请参阅如何选择两种模式之间的行? for alternate and more flexible ways 用于替代和更灵活的方式

awk '/JKL/,/^$/{if($3=="y") $3="NEW"} 1' ip.txt 
  • /JKL/,/^$/ lines of interest /JKL/,/^$/感兴趣的行
    • if($3=="y") if 3rd field value is exactly the string y if($3=="y")如果第3个字段值恰好是字符串y
    • $3="NEW" change the 3rd field value to desired text $3="NEW"将第3个字段值更改为所需文本
    • if you need use regex, use sub(/y/, "NEW", $3) or gsub(/y/, "NEW", $3) 如果你需要使用正则表达式,请使用sub(/y/, "NEW", $3)gsub(/y/, "NEW", $3)
  • 1 idiomatic way to print contents of $0 1打印$0内容的惯用方法

Using GNU awk and split() . 使用GNU awk和split() First some more descriptive test data: 首先是一些更具描述性的测试数据:

...
JKL
 x x y x x
    x  y  z  x  x

...

Then the script: 然后脚本:

$ awk '
/JKL/,/^ *$/ {                 # the desired block 
    n=split($0,a,FS,seps)      # split and store the separators
    b=seps[0]                  # seps[0] has the leading space, init buffer with it
    for(i=1;i<=n;i++) {        # iterate all fields
        if(i==3 && a[i]=="y")  # if 3rd field is y
            a[i]="NEW"         # replace it with with NEW
        b=b a[i] seps[i]       # build the buffer for output
    }
    print b
}' file

and the output: 和输出:

JKL
 x x NEW x x
    x  y  z  x  x

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM