find /source/dir/ -type f -name '*.avi' -exec sh -c 'f="{}"; test ! -f "${f%.*}.idx" && cp "$f" /target/dir/' \;
Este comando encontra todos os arquivos .avi sob o /source/dir/ e gera um shell básico para cada um. O shell então testa se não há um arquivo .idx correspondente e invoca cp quando necessário.
Edit: Eu mudei o comando um pouco para torná-lo mais infalível. Após a solicitação explícita, explico o comando inteiro com mais detalhes.
-
find- Encontre ... -
/source/dir/- ... em um determinado diretório ... -
-type f- ... todos os arquivos ... -
-name '*.avi'- ... com nomes correspondentes a este padrão ... -
-exec- ... e para cada arquivo encontrado, execute ... -
sh ...- ... um shell com seus próprios parâmetros (explicado posteriormente). -
\;- indica onde o-exectermina. O truque importante é: cada string{}é substituída pelo caminho real para o arquivo específico encontrado; é assim quefind -execfunciona.
Cada shell recebe a opção -c , que lhe diz para executar o próximo argumento como se fosse um comando digitado. O shell vê esse comando com {} já substituído pelo caminho do arquivo, conforme explicado acima.
E o comando é assim:
-
f="{}"- Memorize o caminho sob o nomef(lembre-se: neste momento já existe algum caminho em vez de{}). -
;- separador de comandos. -
test- Teste e retorne o status de saída de acordo; os argumentos a seguir dirão o que testar.-
!- Cuidado: o teste está invertido. -
-f- Teste se há um arquivo existente ... -
"${f%.*}.idx"- ... sob este caminho. A construção${f%.*}informa ao shell para obter o conteúdo da variávelfsem o fragmento do último ponto.para o final. Eu adiciono outra extensão. Desta forma eu os troco.
-
-
&&- Apenas se o comando anterior (ou seja,test) retornou o status de saída0... -
cp- ... copie ...-
"$f"- ... o arquivo que foi encontrado porfind... -
/target/dir/- ... para o diretório de destino.
-
Notas finais:
- Eu preciso de um shell para cuidar de
"${f%.*}.idx"e&&. Se eu quisesse copiar todos os arquivos encontrados, então... -exec cp "{}" /target/dir/ \;seria suficiente (e ainda assim longe do ideal, mas não se distraia). - É bom citar (como em
"") todos os caminhos que podem incluir espaços, caracteres especiais, etc. - O argumento (comando) para
shestá entre aspas simples (''). Se if foi colocado entre aspas duplas (""), a expansão de"${f%.*}.idx"ocorreria no shell atual (aquele que executafind) e isso não é o que eu quero. Você pode ler mais aqui .