我错误地附加了 (>>) 而不是覆盖 (>) 处理数千个文件的脚本的输出,但我只对大约 20% 的文件执行了此操作(我运行了该脚本的 5 个并行实例)。基本上我有十行文本,一个空行,然后又是相同的十行文本。
- 我怎样才能找到这些文件?
- 如何删除第二次迭代?
1比2重要得多。
我错误地附加了 (>>) 而不是覆盖 (>) 处理数千个文件的脚本的输出,但我只对大约 20% 的文件执行了此操作(我运行了该脚本的 5 个并行实例)。基本上我有十行文本,一个空行,然后又是相同的十行文本。
- 我怎样才能找到这些文件?
- 如何删除第二次迭代?
1比2重要得多。
(这个问题就说明了问题)
更新:
我仔细看了看内容。这是具有重复内容的文件的结构:
<empty line>
<text>
<empty line>
<empty line>
<same text>
<empty line>
没有重复内容的文件是
<empty line>
<text>
<empty line>
也就是说,中间有两行空行,第一行的起点是上面的文字,第二行的起点是下面的文字。文本的顶部和底部均被一行空行包围。
答案1
在执行其他操作之前,请先备份当前的数据。如果出现任何问题,您可以随时恢复到此副本。例如你可以用来
tar
这样做:tar cfz /path/to/backup-files.tar.gz /path/to/directory-to-backup/
作为一般规则,您应该绝不处理您关心的任何数据的唯一副本。请务必进行备份,或制作副本并在副本上进行操作。换句话说:你应该总是给自己一个简单、最好是快速的方法来恢复任何更改、撤消任何错误。
如果您绝对确定
\n
任何“好”文件中都不会连续出现三个换行符 ( ) 的实例,那么请尝试此操作副本一些“好”和“坏”文件:perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' filenames
这将删除这些文件中从 3 个换行符(即一行文本末尾的换行符后跟两个空行)到文件末尾的所有内容,并将其替换为两个换行符(一个用于结束文本行) ,以及您想要在文件末尾添加的空行)。
任何文件不有 3 个连续的换行符(即它们是不需要修复的“好”文件),将不会被修改。
检查刚刚用 perl 处理的文件(“好”和“坏”)。
如果它们符合您的预期,则对包含您的文件的目录中的所有文件运行 perl 脚本。例如,
find
如果文件都有.txt
扩展名:find /path/to/directory -type f -name '*.txt' -exec \ perl -i -0777 -p -e 's/\n{3,}.*/\n\n/' {} +
(调整
find
命令以适合您的实际目录和文件名)
答案2
使用 GNU awk for multi-char RS 和 ENDFILE 只是为了查找文件:
$ awk -v RS='\n{2}' '$0==p{f=1} {p=$0} ENDFILE{print FILENAME, (f ? "dups" : "uniq"); p=f=""}' file1 file2
file1 dups
file2 uniq
以上是在此输入上运行的:
$ head file{1,2}
==> file1 <==
<text>
<text>
==> file2 <==
<text>
答案3
和perl
:
find . -type f -size +1c -exec perl -l -0777 -e '
while (<<>>) {
$size = length; $half = $size / 2;
if ($size % 2 == 0 && substr($_, 0, $half) eq substr($_, $half)) {
print "$ARGV is one of them";
truncate $ARGV, $half or warn "truncate $ARGV: $!";
}
}' {} +
答案4
在 中zsh
,您可以使用$mapfile
关联数组将文件路径映射到其内容。这样可以轻松比较前半部分和后半部分并就地更新文件。
#! /bin/zsh -
zmodload zsh/mapfile || exit
set +o multibyte
for file in **/*(ND.L+1); do
text=$mapfile[$file]
size=$#text
if (( size % 2 == 0 )); then # even size
(( half = size / 2 ))
if [[ $text[1,half] = $text[half+1,-1] ]]; then
print -r -- $file is one of them
mapfile[$file]=$text[1,half] # or truncate -s$half -- $file
fi
fi
done
(未经测试)。
您可以替换**/*(ND.L+0)
为**/*(ND.L+0m-1)
仅处理过去 24 小时(或**/*(ND.mh-3)
过去 3 小时等)内最后修改的文件。D
如果不需要考虑隐藏文件,请删除。删除或注释掉 ,mapfile[$file]=...
仅列出匹配的文件而不修改它们。