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“
这里有两个步骤(陈述):
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