Bash 当使用变量时,如何防止sed编辑包含模式第一个匹配项的行?

Bash 当使用变量时,如何防止sed编辑包含模式第一个匹配项的行?,bash,sed,Bash,Sed,此sed代码删除所有包含{$line}的行,这些行是通过file.txt找到的: sed -i "/{$pattern}/d" ./file.txt 当前,当$pattern设置为“cat”时,将删除此示例file.txt中的所有行: 我需要对此进行更改,这样它就不会删除包含{$pattern}的第一个找到的行,而是只删除在后面的行中找到的所有后续外观: 例如,假设file.txt是: One day, the {cat} said to the {owl}, "What are you ea

sed
代码删除所有包含
{$line}
的行,这些行是通过
file.txt
找到的:

sed -i "/{$pattern}/d" ./file.txt
当前,当
$pattern
设置为“cat”时,将删除此示例
file.txt
中的所有行:

我需要对此进行更改,这样它就不会删除包含
{$pattern}
的第一个找到的行,而是只删除在后面的行中找到的所有后续外观:

例如,假设
file.txt
是:

One day, the {cat} said to the {owl}, "What are you eating for breakfast, {owl}?"
The {owl} replied, "I am eating {cereal}. Would you like some, {cat}?"
"Yes, I would," replied the {cat}.
So the {cat} and the {owl} ate {cereal}.
如果
$pattern
被设置为“cat”,则输出将如下所示,因为第1行第一次出现“cat”,而所有其他后续行也出现了“cat”,因此它们都被删除:

One day, the {cat} said to the {owl}, "What are you eating for breakfast, {owl}?"
如果将
$pattern
设置为“owl”,则输出将如下所示,因为第1行包含第一个出现的“owl”,第2行和第4行也有实例,这些实例将被删除:

One day, the {cat} said to the {owl}, "What are you eating for breakfast, {owl}?"
"Yes, I would," replied the {cat}.
如果将
$pattern
设置为“谷物”,则删除第4行时,输出将如下所示,因为第4行是唯一一个额外出现“谷物”的行

  • 不能对文件进行排序,因为行的顺序很重要
  • 请注意,第1行包含“owl”的两个副本,但该行上的第二个外观不视为“owl”的第二个外观

有没有办法将
sed
设置为不删除包含
{$patter}
第一次出现的行,而只编辑模式的所有后续出现的内容?

我应该对此进行更多测试。波东在评论中正确地指出


这将跳过每一个$行并删除所有其他内容


根据,您可以执行以下操作:

sed -i '
    /{$line}/,$ {
        /{$line}/n # skip over the line that has "{$line}" on it
        d
    }
' ./file.txt

您需要转义
$d
,否则它将被视为shell变量并由shell展开(可能为空字符串):

使用awk的替代方案:

$ awk "/$line/&&c++ {next} 1" ./file.txt
这可能适用于您(GNU-sed):


使用
$var
作为保持空间中的开关。

使用
GNU sed

sed -ne "/$line/{2,\$p}" -e "/$line/! {p}" file

相关的是的,这几乎可以回答,但是我发现
sed-I/$line/{2,$d}“
导致
sed:-e表达式#1,char 33:unexpected','
{2,$d}
似乎与
sed
上的双引号不兼容,但使用单引号时,
$line
似乎不起作用。是否要删除其中包含$line内容的每一行文本或文件中出现的每一行$line(在这两种情况下,从第二次出现起)。您的问题陈述了内容,但示例陈述了整行内容,回答是这样的?如果“$line”包含文本“.*”,您希望发生什么?如果“$line”被设置为“her”,并且你点击了一个包含“there”的行-这是匹配的行还是不匹配的行?是要删除包含图案的线条,还是仅删除与图案完全匹配的线条,还是要从图案中删除到线条末端或其他内容?请发布一些有代表性的示例输入和预期输出,显示您将关心的这些和其他边缘情况。如果“$line”设置为“her”,这将只匹配标记为“{her}”的项目,而不是类似于“there”或“{there}”,但“t{her}e”将被视为匹配项。请注意,{”和“}”是我之前在文本中放置的标记,以便于此脚本只查找正确的项而忽略其他文本。换句话说,它不需要知道单词边界是什么。我试着运行它,但发现它似乎忽略了
{
}
,只是用
$line
删除任何行。您应该像这样使用
awk
变量:
awk-v var=“$line”$0~var&&c++{next}1.。/file.txt
我认为这并不像您认为的那样。对我来说,它说
如果一行包含$line,并且介于2和文件末尾之间,请打印它。否则,如果它不包含$line,请打印它。
OP希望打印第一个出现的$line,并抑制其余的$line。这将跳过每个$line并删除所有其他内容。
sed -i "/{$line}/{2,\$d}" ./file.txt
$ awk "/$line/&&c++ {next} 1" ./file.txt
sed '/{'"$var"'}/{x;//{x;d};x;h}' file
sed -ne "/$line/{2,\$p}" -e "/$line/! {p}" file