Diff head of files

11

Eu tenho dois arquivos Suspeito que um arquivo seja um subconjunto do outro. Existe uma maneira de diferenciar os arquivos para identificar (de maneira sucinta) onde no primeiro arquivo o segundo arquivo se encaixa?

Richard
fonte
Você quer dizer que as linhas de um arquivo são uma subsequência do outro ou, na verdade, uma substring contígua?
Kaz
Uma substring contígua, @Kaz.
Richard

Respostas:

14

diff -e bigger smaller fará o truque, mas requer alguma interpretação, pois a saída é um "script ed válido".

Eu criei dois arquivos, "maior" e "menor", em que o conteúdo de "menor" é idêntico às linhas 5 a 9 de "maior", fazendo `diff -e maior menor":

% diff -e bigger smaller
10,15d
1,4d

O que significa "exclua as linhas 10 a 15 de 'maior' e exclua as linhas 1 a 4 para ficar 'menor'". Isso significa "menor" são as linhas 5 a 9 de "maior".

Inverter os nomes dos arquivos me deu algo mais complicado. Se "menor" realmente constituir um subconjunto de "maior", apenas os comandos 'd' (para excluir) serão exibidos na saída.

Bruce Ediger
fonte
5

Você pode fazer isso visualmente com meld . Infelizmente, é uma ferramenta da GUI, mas se você quiser fazer isso apenas uma vez e em um arquivo relativamente pequeno, tudo ficará bem:

A imagem abaixo é a saída de meld a b:

insira a descrição da imagem aqui

terdon
fonte
1
Meld é legal, mas não funciona tão bem com arquivos com mais de 100 MB.
Richard
@ Richard não, não e eu preferiria uma ferramenta de linha de comando de qualquer maneira, eu apenas pensei em mencionar.
terdon
Parece muito vimdiff, que está disponível no terminal.
Patrick
2

Se os arquivos forem pequenos o suficiente, você poderá incorporá-los ao Perl e fazer com que seu mecanismo de regex faça o seguinte:

perl -0777e '
        open "$FILE1","<","file_1";
        open "$FILE2","<","file_2";
        $file_1 = <$FILE1>;
        $file_2 = <$FILE2>;
        print "file_2 is", $file_1 =~ /\Q$file_2\E/ ? "" : "not";
        print " a subset of file_1\n";
'

O -0777comutador instrui o Perl a definir seu separador de registros de entrada $/para o valor indefinido, a fim de eliminar completamente os arquivos.

Joseph R.
fonte
1
O que 777faz? Presumo que você está passando NULL como $/mas por quê? Além disso, como são opções esotéricas, uma explicação seria boa para as pessoas não-perl.
terdon
1
@terdon Estou realmente fazendo isso para consumir os arquivos inteiros. Explicação adicionada.
Joseph R.
Mas por que isso é necessário? $a=<$fh>deve beber assim mesmo, certo?
terdon
1
@terdon Não que eu saiba, não. Por padrão, $/é definido como \npara que $a=<$fh>apenas uma linha do arquivo $fhseja aberta. A menos que perlo comportamento da linha de comando do curso tenha padrões diferentes dos quais eu não conheço?
Joseph R.
Argh, sim, meu mal, eu quase nunca sorvo arquivos ou uso o while $foo=<FILE>idioma, então não tinha certeza e executei um teste (errado) que parecia funcionar. Deixa pra lá :).
terdon
1

Se os arquivos são de texto e smaller, dentro de biggerinicia no início de uma linha, não é muito difícil implementar com awk:

awk -v i=0 'NR==FNR{l[n++]=$0;next}
    {if ($0 == l[i]) {if (++i == n) {print FNR-n+1;exit}} else i=0}
    ' smaller bigger
Stéphane Chazelas
fonte
1

Sua pergunta é "Diff head of files". Se você realmente quer dizer que um arquivo é a cabeça do outro, um simples cmpdirá que:

cmp big_file small_file
cmp: EOF on small_file

Isso informa que uma diferença entre os dois arquivos não foi detectada até o final do arquivo ser alcançado durante a leitura small_file.

Se, no entanto, você quer dizer que todo o texto do arquivo pequeno pode ocorrer em qualquer lugar big_file, pressupondo que você possa ajustar os dois arquivos na memória, use

perl -le '
   use autodie;
   undef $/;
   open SMALL, "<", "small_file";
   open BIG, "<", "big_file";
   $small = <SMALL>;
   $big = <BIG>;
   $pos = index $big, $small;
   print $pos if $pos >= 0;
'

Isso imprimirá o deslocamento no local big_fileonde o conteúdo small_fileestá localizado (por exemplo, 0 se small_filecorresponder no início de big_file). Se small_filenão corresponder ao interior big_file, nada será impresso. Se houver um erro, o status de saída será diferente de zero.

jrw32982 suporta Monica
fonte