Regex 如果两个模式之间存在字符串,则bash delete

Regex 如果两个模式之间存在字符串,则bash delete,regex,bash,sed,Regex,Bash,Sed,我一直在尝试使用sed来完成以下任务。假设我有以下文件(注意:我的实际文件比这个复杂): 我想检查两个模式之间是否存在target,在本例中,在foo bar和done行之间(包括两行),如果target确实存在,则删除整个模式 我知道如何使用此sed命令删除两个模式之间的行: sed '/people.*/,/done/d' file 但我只想在两个字符串匹配之间存在字符串target时删除它 我的逻辑是这样的: sed -n '/people.*/,/done/p' file | chec

我一直在尝试使用
sed
来完成以下任务。假设我有以下文件(注意:我的实际文件比这个复杂):

我想检查两个模式之间是否存在
target
,在本例中,在
foo bar
done
行之间(包括两行),如果
target
确实存在,则删除整个模式

我知道如何使用此
sed
命令删除两个模式之间的行:

sed '/people.*/,/done/d' file
但我只想在两个字符串匹配之间存在字符串
target
时删除它

我的逻辑是这样的:

sed -n '/people.*/,/done/p' file | check if target string exists | delete entire pattern found by sed
编辑

我忘了提到在同一行中,
target
之前和
target
之后可以有任意数量的单词。

Sed

如果在
$pattern
中找到
$pattern
,则将从
$start
删除到
$end

sed:a;N;\$!ba;s/$start.*$pattern.*$end//g“

这里有两个步骤(陈述):

  • 将整个文件作为单个字符串读取(根据文件大小的不同,可能不正确)。有关非常好的解释,请参阅。唯一的区别是在$之前增加了反勾号!ba,使其使用双引号,这对于在sed行内传递Bash变量很有用
  • 常规的旧搜索/替换
  • Perl

    要处理ungreedy匹配,如果允许使用Perl,请使用:

    perl-0777-p-e的/$start.*?$pattern.*?$end//s'


    这也会将整个文件作为字符串读取。结尾的/s告诉它将换行作为正则表达式匹配的一部分。使用。*而不是。*?返回贪婪搜索。

    如果文件多次包含
    done
    ,则可以在不首先将整个文件读入内存并引发贪婪匹配问题的情况下执行此操作

    sed '/^people/ { :loop; N; /\ndone/ ! b loop; /target/ d }' filename
    
    在Mac OS X上,显然有必要在右括号前加一个换行符,这样您可以将代码放入多行字符串文字:

    sed '/^people/ { :loop; N; /\ndone/ ! b loop; /target/ d 
    }' filename
    
    或者将代码的这个版本(在任何情况下都更可读)放在一个文件中,比如说
    foo.sed
    ,并使用
    sed-f foo.sed文件名

    /^people/ {
      :loop
      N
      /\ndone/ ! b loop
      /target/ d
    }
    
    该守则的运作如下:

    /^people/ {
    
    以“人”开头的一行

    在循环中提取更多行,直到其中一行以
    done
    开始(这将是
    \n一行
    第一次出现在模式空间中)

    如果在所有这些中的某个地方有
    target
    ,那么就放弃整个东西

    }
    
    否则照常进行(这意味着打印图案空间,因为我们没有将
    -n
    传递给sed)

    鲁棒性的一个可能改进是

    sed '/^people/ { :loop; N; /\ndone$/! { $! b loop }; /target/ d }' filename
    


    通过更改
    /\n完成$/!{$!b loop}
    。这将在文件的最后一行结束循环,即使没有遇到
    done
    ,这会导致文件末尾未完成的
    人员
    部分不会被丢弃(除非它们包含
    目标
    ).

    sed是一种用于在一条线上进行简单替换的优秀工具,但在20世纪70年代中期,当awk发明时,它用于处理多条线上的所有结构都已过时,因此只需使用awk即可实现简单性、清晰性、健壮性等。例如,使用GNU awk实现多字符:

    $ awk -v RS='^$' '{sub(/\nfoo bar\n.*target.*\ndone\n/,""); print}' file
    hello world
    

    迟交的答复

    sed '/^foo bar *$/,/^done *$/{/^done *$/!{H;d};/^done *$/{H;g;s/.*//g;x;/.*target.*/d;s/^.//g}}'
    
    查找
    /^foo bar*$/,/^done*$/

    /foo bar/,/done/
    
    /^done*$/!{H;d}
    从foo-bar中取出所有行,但不是最后一行“done”,并将其放入保留空间。然后从图案空间中删除这些线

    这个
    /^done*$/{H;g;s/*///g;x;
    取最后一行“done”然后将其附加到保留空间。现在我们有了从line foo bar到保留空间中完成的line的所有线条。之后,我们清除patter空间中的所有线条,并将保留空间中的线条范围与pattern空间中的空行进行交换(这是为了在“foo-bar”和“done”之间的另一个行范围内定位时,始终保持保留空间为空

    最后

    /.*target.*/d 
    
    我们测试看看“target”是否在mutli模式空间中。如果是,则删除“foobar”和“done”之间的行范围

    这样可以避免将整个文件作为单个字符串读取

    示例

    hello world
    foo bar
    people people
    target
    something
    done
    foo bar
    .....
    .....
    .....
    done
    foo bar
    people people
    test
    something
    done
    
    结果

    hello world
    foo bar
    .....
    .....
    .....
    done
    foo bar
    people people
    test
    something
    done
    

    注意:从“foo-bar”到“done”的行范围,以及包含“target”的行正在被删除

    你的意思是删除
    完成
    之间的所有内容,或者只删除
    目标
    行人和
    完成
    之间的所有内容,包括
    完成
    工作完美……我知道
    N
    做什么,但你能补充一点解释吗关于
    :a
    $!ba
    如果文件后面的某个地方有另一个
    完成了
    ,这会不会很难匹配?True.sed无法处理不加密的匹配。因为这一个将必须移动到PCRE正则表达式引擎。可能是Perl或Python?您的答案对于我上面提供的示例非常有用,但不幸的是它匹配贪婪在我尝试过的其他一些文件上:(这个答案看起来不错,但是当我尝试运行它时,我得到了这个错误:
    sed:1:“/^people/{:loop;N;…”:意外的EOF(挂起的})
    …有什么原因吗?顺便说一句,我在使用OSx。是的,我误读了这个错误(因此忍者删除).等等。我没有办法测试OSX,但可能在某个地方有一个差异文档。如果在最后的
    d
    之后添加一个
    是否有效?不,仍然会出现相同的错误,我想这可能与
    有关{
    方括号,我以前在使用sed时遇到过问题。好的,我在我的FreeBSD虚拟机(它显然与OSX具有相同的sed)中尝试过。如果您将可读版本的代码放入一个文件并使用
    s,它就会起作用
    
    /foo bar/,/done/
    
    /.*target.*/d 
    
    hello world
    foo bar
    people people
    target
    something
    done
    foo bar
    .....
    .....
    .....
    done
    foo bar
    people people
    test
    something
    done
    
    hello world
    foo bar
    .....
    .....
    .....
    done
    foo bar
    people people
    test
    something
    done