如何从出现特定模式的行开始剪切文件?

Ned*_*d64 7 sed files ed

我有大量文件需要减小大小。我发现大多数(不是全部)文件都有一个结束部分,可以在不丢失信息的情况下进行剪切:

Data 1
Data 2
something_unimportant_here END DATA
Rubbish 1
Rubbish 2
Run Code Online (Sandbox Code Playgroud)

如何通过删除包括“END DATA”在内的行和所有后续行,就地,仅更改包含该模式的文件,从而最大限度地减少对磁盘的写访问(许多,许多)来编辑文件(因此,全部)文件和慢速磁盘)。

如果可能,我想在文件中添加一个新的最后一行(我自己的结束标记),以便文件的语法保持正确——同样,仅在包含该模式的文件中。

我正在考虑使用ed,比如

echo ',s/END DATA/ ???? '\\n'q'\\n'wq' | ed "$file"
Run Code Online (Sandbox Code Playgroud)

但似乎无法管理???部分更正。

预期输出:

Data 1
Data 2
NEW END
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 8

您应该能够通过只是截断文件到位,做到这一点,而无需编写文件的新副本一样sed -i/ perl -i/ ed/gawk -i inplace会做。与perl

find . -name '*.txt' -type f -exec perl -ne '
  BEGIN{@ARGV=map{"+<$_"}@ARGV} # open files in read+write mode in the
                                # while(<>) loop implied by -n
  if (/END DATA/) {
    seek ARGV,-length,1; # back to beginning of matching line
    print ARGV "NEW END\n";
    truncate ARGV, tell ARGV;
    close ARGV; # skip to next file
  }' {} +
Run Code Online (Sandbox Code Playgroud)

这最大限度地减少了 I/O,perl因为一旦找到匹配项就停止读取,并且 NEW END\n是它唯一写入的内容。它还写入到位,因此文件元数据(所有权、权限、acls、稀疏性...)被保留并且硬链接不会被破坏。

随着-exec {} +我们也尽量减少数量perl调用。


ste*_*ver 6

听起来您正在寻找的命令序列是

/END DATA/,$d
q
.a
NEW END
.
wq
Run Code Online (Sandbox Code Playgroud)

或作为单线

printf '%s\n' '/END DATA/,$d' 'q' '.a' 'NEW END' '.' 'wq'
Run Code Online (Sandbox Code Playgroud)

(您可以替换wq,p测试。)

前任。给予

$ cat file
Data 1
Data 2
something_unimportant_here END DATA
Rubbish 1
Rubbish 2
Run Code Online (Sandbox Code Playgroud)

然后

$ printf '%s\n' '/END DATA/,$d' 'q' '.a' 'NEW END' '.' 'wq' | ed -s file
Run Code Online (Sandbox Code Playgroud)

$ cat file
Data 1
Data 2
NEW END
Run Code Online (Sandbox Code Playgroud)


Sun*_*eep 6

随着GNU grepGNU sed

grep -lZ 'END DATA' *.txt | xargs -0 sed -i -e '/END DATA/,${//i foo' -e 'd}'
Run Code Online (Sandbox Code Playgroud)

其中*.txt假设您的所有文件都在以.txt扩展名结尾的当前目录中。如果需要递归搜索文件,GNU grep也支持-r/-R选项。

/END DATA/,$ 经营范围

//i foo这里//将匹配先前使用的正则表达式,即/END DATA/i根据需要命令将添加新的结束标记

由于i命令必须由换行符分隔,-e选项用于分隔d命令以删除范围匹配的所有行

作为替代,您也可以使用它,但一次只会将一个文件传递给sed

grep -lZ 'END DATA' *.txt | xargs -0 -n1 sed -i -e '/END DATA/{i foo' -e 'Q}'
Run Code Online (Sandbox Code Playgroud)