我有很多文件夹和文件夹包含文件。同一行可能在单个文件和/或多个文件中出现多次。文件没有排序。因此,在多个文件中重复了一些行,并且这些文件位于不同的文件夹中。
我想要删除重复的行,并只保留其中的一个跨所有文件。此外,文件结构和名称应该保持不变。
我试过了,但只在每个文件中唯一,而不是在所有文件中。此代码使每个文件中的行都是唯一的,并保留文件名:
for i in $(find . -type f); do
awk '!seen[$0]++' "$i" > tmp_file
mv ./tmp_file "$i"
done问:如何在保持文件结构和名称的同时,使所有子文件夹中的所有文件的行都是唯一的?
这是我的文件样本。为了简化起见,我只列出这里的文件,但是文件位于相同或不同的文件夹中。
输入:
$ cat File-1
1
2
3
1
$ cat File-2
2
3
4
1
$ cat File-3
2
4
5
6输出:
$ cat File-1
1
2
3
$ cat File-2
4
$ cat File-3
5
6在我的例子中,保留行的第一次出现是首选的,但不是必需的(保留行可以在任何文件中)。
发布于 2020-07-15 07:54:50
#!/usr/bin/perl
use File::Find;
my $headdir="/some/path";
my @files=();
my $lines={};
find( { wanted => sub { push @files, $_ }, no_chdir => 1 }, $headdir );
foreach my $file (@files) {
next unless(-f $file);
system "cp $file $file". ".old";
open(my $fhin, "$file".".old");
open(my $fhout, ">$file");
while(<$fhin>) {
if(not defined $lines->{$_}) {
print $fhout $_;
$lines->{$_} = 1;
}
}
close($fhin);
close($fhout);
#optional: system("rm $file".".old");
}编辑:(仅)使用问题中提到的文件进行测试,需要对代码进行微小的更改
发布于 2020-07-15 13:59:21
只有当要处理的文件数量小到足以使find运行awk一次时,以下内容才能工作。它还假设您可以复制整个文件树(即,您不受存储限制)。
假设您的文件树位于orig目录中:
$ cp -pr orig tmp
$ cd tmp
$ find . -type f -exec awk '
BEGIN { print ARGC }
FILENAME != fn {
close( "../orig/"fn )
printf "" > ( "../orig/"FILENAME )
}
!seen[$0]++ { print > ( "../orig/"FILENAME ) }
{ fn = FILENAME; }' {} +一旦您对结果感到满意,就可以使用rm -r tmp。
print ARGC用于显示调用awk的次数。ARGC是命令行参数数组中元素的数量(包括脚本本身);看到它多次打印就意味着全局行重复失败。(实际上,如果可以计算要处理的文件总数,则可以将该块更改为if ( (ARGC - 1) < total_number_of_files) exit,以确保如果要多次调用awk,则不会修改任何文件)。
https://unix.stackexchange.com/questions/598526
复制相似问题