Como verificar se arquivo1 é um prefixo de arquivo2?

13

Eu tenho dois arquivos com tamanhos 124665 e 124858 em bytes e quero verificar se file1 é um prefixo de file2 ou não.

tvorog
fonte

Respostas:

11

Supondo que você tenha o tamanho de file1na variável FILE1_SZe sua headimplementação suporte a opção (não padrão) -c:

if head -c "$FILE1_SZ" file2 | cmp -s - file1; then
    echo "file1 is a prefix of file2"
else
    echo "file1 is not a prefix of file2"
fi
Joseph R.
fonte
@ StéphaneChazelas Você pode explicar por cmpque seria melhor do que diffaqui?
Joseph R.
7
Porque cmpfaz uma comparação simples de byte a byte e retorna assim que encontra uma diferença, enquanto diffé um utilitário de texto que usa um algoritmo complexo para mostrar todas as diferenças entre os dois arquivos dos quais você não se importa.
Stéphane Chazelas
12

Se o seu sistema possui o cmpcomando do GNU diffutils, uma opção é

cmp -n 124665 file1 file2

comparar no máximo os primeiros 124665 bytes dos dois arquivos e relatar se eles diferem - ou, mais geralmente

cmp -n "$(wc -c < file1)" file1 file2
chave de aço
fonte
@StephaneChazelas Estou me adivinhando aqui em segundo lugar, mas teria sido melhor sugerir $(stat -c %s file1)o tamanho em bytes? Será que wcrealmente abrir e processar todo o arquivo para obter a contagem de bytes?
steeldriver
2
não, a maioria das wcimplementações otimizará esse caso e executará um fstat()(ou / e a lseek(SEEK_END)), portanto, será o mais eficiente possível. Por outro lado, isso stat -cé específico do GNU.
Stéphane Chazelas
1
Embora se você precisar do específico do GNU cmp, você possa razoavelmente assumir que ele é específico stat.
Barmar
3

O GNU cmppode resolver o problema de uma maneira mais fácil:

cmp file1 file2

Existem quatro saídas possíveis (exceto algum tipo de erro).

  • Sem saída: os arquivos são idênticos.

  • cmp: EOF on file1: arquivo1 é um prefixo do arquivo2.

  • cmp: EOF on file2: arquivo2 é um prefixo de arquivo1.

  • file1 file2 differ: byte NNN, line MMM: Nem um prefixo do outro.

Infelizmente, isso é um pouco estranho de usar em um script, pois esses casos não parecem se distinguir no código de saída. Além disso, as EOF on file1mensagens vão para stderr, enquanto as file1 file2 differmensagens vão para stdout.

Presumo que outras versões do cmpfaçam algo semelhante, mas não verifiquei.

Nate Eldredge
fonte
1
cmpnão é um comando exclusivo do GNU nem foi originado lá, ele já estava na primeira versão do Unix no início dos anos 70. A -nopção é específica do GNU.
Stéphane Chazelas
Você poderia fazercmp file1 file2 2>&1 | grep EOF on file1
David Z
@ StéphaneChazelas: Isso é verdade. Eu não quis dizer que isso cmpera exclusivo do GNU, apenas que o GNU cmpera a única versão que eu tentei. Eu adicionei uma frase para esclarecer.
Nate Eldredge
@ DavidZ: Sim, você poderia, mas fica um pouco menos robusto. Imagine que você está tentando fazer isso com dois arquivos fornecidos pelo usuário, e um deles é nomeado file1e o outro é nomeado file12. (Ou pior ainda, e se o segundo arquivo é chamado EOF on file1?) Resolver este robustamente usando cmpé provavelmente muito mais problemas do que escrever o programa 5-line óbvio em C ...
Nate Eldredge
Pode haver contextos em que um programa C não seja prático. E não é tão difícil torná-lo bastante robusto, porque a produção de cmpé tão fortemente restrita. Usar a -xopção greppara corresponder à linha inteira resolverá todos os casos, exceto os mais exóticos (por exemplo, novas linhas no nome do arquivo).
David Z