删除与模式匹配的每行中的第 N 行

删除与模式匹配的每行中的第 N 行

我在同一目录中有多个文件,例如file1, ...等,每个文件可能包含多行匹配。 我想从每行中删除第 th 行,例如与=和内容匹配file2PATTERN
NPATTERNN3file1

1 no match
2 PATTERN
3 same PATTERN
4 no match here
5 no match here either
6 another PATTERN
7 again, no match
8 no
9 last line

预期输出是

1 no match
2 PATTERN
3 same PATTERN
4 no match here
7 again, no match
8 no

就地编辑文件是一种奖励,而不是一项要求(尽管gnu我知道至少有一种工具可以一次性编辑所有文件......)


有人问了类似的问题这里然而这是一种特殊情况(每个文件中只有一个行匹配模式,并且那里的解决方案仅适用于多行匹配模式,如果它们至少由+1 不匹配的行)。

答案1

我相信你可以awk这样使用:

awk -vN=3 '/PATTERN/ {skips[FNR+N]=1;} {if(!(FNR in skips)) print;}' <file>

所以每次我们点击时,PATTERN我们都会记录远离这里的行N,并且只打印那些我们没有标记为跳过的行。

使用 gawk,您也可以使用-i inplace它来就地完成

正如您所指出的,这不能处理多个文件。当然,您可以用一个for循环来迭代所有文件,但如果没有足够的文件使命令行太长,您也可以这样做:

 awk -vN=3 '{if(FNR==1) split("", skips, ":");} /PATTERN/ {skips[FNR+N]=1;} {if(!(FNR in skips)) print;}' *

skips每次达到 1 时,我们都会重置为空数组FNR,即每个文件的开头。
gnu awk可以将其写为:

gawk -i inplace 'FNR==1{delete nr};/PATTERN/{nr[FNR+3]++};!(FNR in nr)' file*

答案2

我喜欢 2 遍机制,所以我们可以使用sed -i

for file in file1 ...
do sed -i "$file" -e "$(awk <"$file" -v N=3 '/PATTERN/{ print (NR+N) "d" }')"
done

答案3

for f in file1 file2 file...; do
  sed -i -f <(grep -n PATTERN "$f" | while IFS=: read line rest; do printf "%dd; " $((line+3)); done) "$f"
done

将其分开:

  1. 循环遍历 file1 file2 文件...

  2. 在进程替换中构建 sed 表达式,最终针对文件运行。

  3. grep输出与文件中的 PATTERN 匹配的行号(以及实际匹配的行)。

示例输出:

2:2 PATTERN
3:3 same PATTERN
6:6 another PATTERN
  1. while 循环去掉行号,丢弃匹配的行,然后将其发送到 printf,增加 3

  2. printf 打印目标行号,后跟 sed ddelete 命令和分隔分号。

示例输出(作为 的输入sed):

5d; 6d; 9d;

这种方法具有很大的灵活性;您可以设置N=3并用作$((line+N))printf 参数。

为了说明就地编辑,我假设 sed 支持-i“就地”编辑。

答案4

这个用例只是乞求用于使用ex.

不幸的是,自从删除第三行给定的行可能会删除包含 PATTERN 的行,从而导致与该行相关的删除被跳过(或更糟糕的是,删除不正确的行),您需要tac首先使用eg 反转文件。然后删除第三行就可以了PATTERN 的每个实例,并再次反转文件:

for f in *.txt; do printf %s\\n '%!tac' 'g/PATTERN/-3d' '%!tac' x | ex "$f"; done

如果你有tac可用的,我认为这是最干净的解决方案。


完全符合 POSIX 标准的解决方案,利用我的回答:

你可以这样做:

for f in *.txt; do printf %s\\n '%!sed -n '\''1h;1\!{x;H;};${g;p;}'\' 'g/PATTERN/-3d' '%!sed -n '\''1h;1\!{x;H;};${g;p;}'\' x | ex "$f"; done

可读性不是很好,但很实用。

相关内容