Recursivamente compare o conteúdo do diretório por nome, ignorando as extensões de arquivo

7

Eu tenho um diretório contendo cerca de 7.000 arquivos de música. Eu usei coxo para recursivamente recodificar todos os arquivos nele para um diretório separado, gerando todos os arquivos com o mesmo caminho relativo e nome do arquivo. Os arquivos de saída têm uma extensão .mp3, mas alguns dos arquivos de entrada tinham extensões diferentes (.wma, .aac, etc).

Eu posso ver que há uma diferença de contagem de arquivos de ~ 100 arquivos ausentes no diretório de saída. O que eu quero fazer é executar uma comparação dos dois diretórios e obter uma lista dos arquivos que existem na origem, mas não no destino. Isso seria bastante simples, exceto que eu preciso ignorar as diferenças na extensão do arquivo.

Eu tentei usar o rsync com o dry-run ativado, mas não consegui descobrir uma maneira de ignorar as extensões de arquivo. Eu também tentei diff, mas não consegui encontrar uma opção para verificar apenas pelo nome, mas ignorar as extensões de arquivo. Comecei a pensar que eu poderia fazer um ls recursivo em ambos os diretórios, remover as extensões de arquivo e comparar as saídas, mas realmente não tenho idéia de por onde começar a modificar a saída ls usando sed ou awk.

    
por Robert S Ciaccio 26.11.2010 / 22:46

1 resposta

7

Para ver uma listagem, aqui estão duas variantes, uma que recorre a subdiretórios e outra que não. Todos usam sintaxe específica para bash, ksh e zsh.

comm -3 <(cd source && find -type f | sed 's/\.[^.]*$//' | sort) \
        <(cd dest && find -type f | sed 's/\.[^.]*$//' | sort)
comm -3 <(cd source && for x in *; do printf '%s\n' "${x%.*}"; done | sort) \
        <(cd dest && for x in *; do printf '%s\n' "${x%.*}"; done | sort)

Mais curto, em zsh:

comm -3 <(cd source && print -lr **/*(:r)) <(cd dest && print -lr **/*(:r))
comm -3 <(print -lr source/*(:t:r)) <(print -lr dest/*(:t:r))

O comando comm lista as linhas comuns a dois arquivos ( comm -12 ), que estão apenas no primeiro arquivo ( comm -23 ) ou que estão apenas no segundo arquivo ( comm -13 ). Os números indicam o que é subtraído da saída¹. Os dois arquivos de entrada devem ser classificados.

Aqui, os arquivos são, na verdade, a saída de um comando. O shell avalia a construção <(…) fornecendo um arquivo “falso” (um FIFO ou um descritor de arquivo /dev/fd/ ) como argumento para o comando.

Então aqui os menos sayers são totalmente justificados.

Se você deseja executar ações nos arquivos, provavelmente desejará iterar os arquivos de origem.

cd source
for x in *; do
  set -- "…/dest/${x%.*}".*
  if [ $# -eq 1 ] && ! [ -e "$1" ]; then
    echo "$x has not been converted"
  elif [ $# -gt 1 ]; then
    echo "$x has been converted to more than one output file: " "$@"
  else
    echo "$x has been converted to $1"
  fi
done
    
por 26.11.2010 / 23:20