我有一个名为 file_a.txt 的文本文件。我的第一个命令是
grep -A 12 ".production =" file_a.txt
输出是几个块。每个字符串块包含 13 行
grep
我特别想删除使用原始文件 file_a.txt 中的命令获得的所有字符串块。我不想将 grep 输出发送到新文件。我也不想使用,grep -v
因为它在我的情况下不起作用。
我尝试过类似的事情,但没有任何效果:
cut < grep -A 12 ".production =" file_a.txt
sed -i '/`grep -A 12 ".production ="`/d' file_a.txt
答案1
GNU sed 方式
在GNU sed
(如果您使用的是某些 Linux 发行版,它应该是默认sed
实现),您可以使用如下内容:
sed '/.production =/,+12d' inputfile.txt
怎么运行的:
- 它逐行扫描输入文件(这就是 sed 的工作原理)并检查是否应该使用该命令。
- 我们的命令是
d
(最后一个字符),这意味着删除该行。 - 但只有当前行与我们的范围匹配时,此命令才会运行。
- 该范围由两个以字符分隔的参数(包括范围的开始和结束)指定
,
。第一个是正则表达式/.production =/
,它匹配包含该表达式的每一行。第二个参数是+12d
which的意思12 lines from start range
。 - 因此,我们的范围匹配与表达式匹配的每一行以及接下来的 12 行并删除它们。
- 所有其他行都打印到输出(默认
sed behaviour
)。
便携,丑陋的方式
这个应该适用于其他sed
实现,但涉及更多的输入并且不是那么健壮:
sed '/.production =/{N;N;N;N;N;N;N;N;N;N;N;N;d}' somefile.txt
怎么运行的:
- 它逐行扫描输入文件(这就是 sed 的工作原理)并检查是否应该使用该命令。
- 它检查该行是否与
/.production =/
模式匹配。如果是这样,它将运行大括号中的所有命令{}
。 - 我们运行
N
comamnd 12 次。N
命令读取下一行并将其附加到当前缓冲区。因此,运行 12 次后,当前缓冲区中连接了 13 行(第一行 + 由N
命令读取的 12 行)。 - 现在我们运行
d
命令来删除这串联的 13 行。 sed
继续,直到找到另一个模式并再次删除 13 行。所有其他行均被打印(默认sed
行为)。
答案2
您可以检索要开始过滤的行号,然后使用 AWK 对其进行过滤。
在 AWK 中,NR 表示记录号,默认为行尾 (\n)。
START_LINE=$(cat file_a.txt | grep -n .production | cut -f1 -d:)
cat file_a.txt | awk '{ if(NR < '$START_LINE' || NR > '$START_LINE' + 12) print $0; }'
答案3
当 grep 和 sed 不能完全解决问题时,可以使用 awk。 awk 可以轻松模拟大多数文本实用程序(sort
这是主要的例外),并且可以以比管道更灵活的方式组合它们。
awk '
/.production =/ {skip_lines = 13}
skip_lines {--skip_lines}
!skip_lines {print}
' file_a.txt >file_a.txt.new &&
mv file_a.txt.new file_a.txt
答案4
您可以在 Ex 模式下使用 Vim:
ex -sc '/.production =/d13|x' file_a.txt
//
移动到匹配行13
选择13行d
删除x
保存并关闭