我有大量文件需要缩小。我发现大多数(不是全部)文件都有一个结尾部分,可以在不丢失信息的情况下进行剪切:
Data 1
Data 2
something_unimportant_here END DATA
Rubbish 1
Rubbish 2
如何通过删除包含“END DATA”的行以及所有后续行来编辑文件(因此全部结束),就地,仅更改那些包含该模式的文件,从而最大限度地减少对磁盘的写访问(很多很多文件和慢速磁盘)。
如果可能的话,我想在文件中添加一个新的最后一行(我自己的结束标记),以便文件的语法保持正确——同样,仅在那些包含该模式的文件中。
我正在考虑使用ed
,比如
echo ',s/END DATA/ ???? '\\n'q'\\n'wq' | ed "$file"
但似乎无法管理???? 部分正确。
预期输出:
Data 1
Data 2
NEW END
您应该能够通过在原地截断文件来做到这一点,而不必像
sed -i
//perl -i
/那样编写文件的新副本ed
。gawk -i inplace
与perl
:这将 I/O 最小化,
perl
因为一旦找到匹配项就停止读取,并且NEW END\n
是它唯一写入的内容。它还写入到位,因此文件元数据(所有权、权限、acls、稀疏性......)被保留,硬链接不会被破坏。-exec {} +
我们还可以最大限度地减少perl
调用次数。听起来您正在寻找的命令序列是
或作为单线
(您可以替换
wq
为,p
进行测试。)前任。给定
然后
给
GNU grep
和_GNU sed
where假设您的所有文件都在以扩展名
*.txt
结尾的当前目录中。.txt
如果需要递归搜索文件,GNU grep
也支持-r/-R
选项。/END DATA/,$
运营线路范围//i foo
这里将匹配之前使用的正则表达式,//
即命令将根据需要添加新的结束标记/END DATA/
i
由于
i
命令必须用换行符分隔,-e
因此选项用于分隔d
命令以删除与范围匹配的所有行作为替代方案,您也可以使用它,但一次只能将一个文件传递给
sed
:保持简单,只需将 awk 用于文件操作部分,例如,使用 GNU find、awk、grep 和 xargs:
或在每个文件的末尾打印您自己的结束标签:
这个
python
3.8 解决方案松散地基于 Stephane 的就地truncate
解决方案,但有几个区别 1. 代码不依赖外部实用程序进行目录遍历 2. 文件是内存映射的,以便于定位END DATA
字符串将代码放在
.py
文件中,并将目录名称作为参数传递结合Sundeep 的回答和Ed Morton 的回答,但没有
xargs
:find
,当然,选择文件。默认情况下,它会递归搜索指定的director。要仅搜索当前目录,-maxdepth 1
请在.
.grep -q
q如果文件包含正在搜索的模式 ( ),则以“成功”退出状态退出,END DATA
否则以“假”退出。-a
表示“AND”,就像&&
在 shell 命令行中一样。它的意思是“如果(仅当)之前的事情成功了,就做下面的事情”。实际上,它是find
谓词(测试/操作)之间的默认连接运算符,因此您可以将其省略。我包括它只是为了清楚起见。sed
,从 Sundeep 的答案逐字复制的命令(但foo
更改为NEW END
)仅在包含END DATA
字符串并满足其他find
测试的文件上执行。-exec … +
导致sed
对多个文件调用一次,就像xargs
它一样。请注意,我们不能
-exec … +
与该grep
命令一起使用,因为它不允许测试退出状态。使用 awk 查找模式的偏移量,并
dd
在该点截断文件并附加新的预告片:nextfile
使用支持(gawk
,bwk
, [1] 的某些版本)的 awk 实现mawk
,可以通过将批量文件传递给 awk 来更有效地完成:代替 icky
2>/dev/null
status=noxfer
可以与dd
支持它的实现一起使用。引用 kludge 和环境变量传递是一团糟,它可以使用一些改进。
[1]:根据 GNU awk手册,mawk 也应该支持它。但是,来自 Debian 10 的旧版本的 mawk 不支持它。
如果这是一次性任务,则可以方便地使用
vi
:首先,找到包含所需内容的行(使用搜索
/
或?
)要删除当前行之后到文件末尾的所有行,请按
d
G
。要删除从文件开头到当前行的所有行,请按
d
gg
。保存并退出
:wq