Сравните содержимое файлов и удалите более короткие - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть тысячи .txt файлов. Я хочу удалить некоторые из них. Некоторые файлы похожи - тот же контент, но один длиннее, и мне нужно удалить более короткий. Все файлы лежат в одной папке.

Единственное, что известно об этих файлах, это то, что один файл может иметь содержимое

ABCDEFGH

и другой

ABCDEF

но не

XYZ

Что мне нужно сделать, это удалить файл ABCDEF, который имеет аналогичный более длинный файл ABCDEFGH. Я ожидаю n * (n-1) сравнения. Предположим, что файлы должны сравниваться в двоичном виде. Есть ли скрипт в bash (или вообще Linux), который мог бы сделать это для меня? Если бы мне пришлось это сделать, я написал бы консольное приложение C #, чтобы сравнить все файлы и удалить похожие, но более короткие, но я думаю, что это будет проще и быстрее в bash-скрипте (или в Linux). Внешние инструменты разрешены. Если файлы имеют одинаковое содержимое и одинаковую длину - один из файлов должен оставаться в папке. Существует вероятность, что будет 3 или более файлов (с одинаковым содержимым) и (одинаковой длины или разной длины).

Ответы [ 3 ]

0 голосов
/ 25 апреля 2018

Ваш вопрос не указывает, говорите ли вы об именах файлов или содержимом файлов. Я предполагаю имена файлов, поскольку это возможно в виде одной строки.

Может подойти следующее:

$ shopt -s nullglob
$ for f in *; do for x in "$f"?*; do rm -v "$f"; continue 2; done; done
  • Выполняет пошаговый просмотр списка файлов (*), присваивая каждому из них $f.
  • Для каждого файла используется один цикл внутреннего цикла for для определения существует ли более длинная версия имени файла.
  • Если более длинная версия существует, более короткая версия удалена, и мы продолжаем внешний цикл.

Параметр оболочки nullglob избавляет нас от необходимости проверять наличие файла $x.

0 голосов
/ 02 ноября 2018

Любой, кто заинтересован в таком Perl-скрипте, будет счастлив.Я предполагаю, что у нас есть скрипт в текущей папке с файлами * .txt.Если файл такой же, как любой другой, но длиннее или короче, поэтому в одном из файлов есть данные, которые делают его длиннее, но не отличаются для передней части, тогда более короткий файл будет удален.Для файлов 1,3 МБ и 1300 Cygwin Perl потребовалось менее 2 минут, чтобы просмотреть все файлы.Файлы сравниваются построчно.Сценарий ниже:

#!/usr/bin/env perl
use strict;
use warnings;

my @files = <*.txt>;
my @del;
my $diff;
foreach my $file1 (@files) {
        foreach my $file2 (@files) {
                if ($file1 eq $file2) {
                        last;
                }
                open my $fh1, $file1 or die "can't open $file1: $!";
                open my $fh2, $file2 or die "can't open $file2: $!";
                print "Comparing $file1 and $file2...";
                my $line1;
                my $line2;
                $diff=0;
                while($line1 = <$fh1>) {
                        $line2 = <$fh2>;
                        if ($line1 ne $line2) {
                                print "different!\n";
                                $diff=1;
                                last;
                        }
                }
                if ($diff == 0) {
                        print "the same till end of one files!\n";
                        if (-s $file1 >= -s $file2)
                        {
                                push @del, $file2;
                        }
                        if (-s $file1 < -s $file2)
                        {
                                push @del, $file1;
                        }
                }
                close($fh1);
                close($fh2);
        }
}
foreach my $file (@del) {
        print "Removing $file\n";
        unlink $file;
}

Обратите внимание, что кодировка файлов и окончания строк могут отличаться, поэтому все файлы, например, должны быть в кодировке UTF-8, а окончания строк должны быть одинаковыми - LF.

0 голосов
/ 25 апреля 2018

Попробуйте следующий скрипт (я не включил команду rm, только echo для тестирования):

#!/usr/bin/env bash

# Create some files for testing
touch ABCDEF                                                             
touch ABC
touch ACB
touch XABC  
touch XYZ                                                                                                                      
touch XY 

for fname1 in *; do                                                      
    for fname2 in *; do                                                  
        if [[ "$fname2" != "$fname1" && "$fname2" =~ "$fname1" ]]; then  
            echo -e "Short: $fname1 \tLong: $fname2"
        fi                                                               
    done                                                                 
done 

Этот скрипт будет искать только файлы в текущем каталоге. Выход:

Short: ABC    Long: ABCDEF                                                  
Short: ABC    Long: ABCDEFGH 
Short: ABC    Long: XABC                                               
Short: ABCDEF Long: ABCDEFGH                                             
Short: XY     Long: XYZ 

Если вы хотите удалить «короткие» файлы, замените строку echo на

rm -i "$fname1" 2>/dev/null                                              

Я не оптимизировал этот код, поэтому он может быть неэффективным. Пожалуйста, дайте мне знать, если это так, и я постараюсь улучшить его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...