Localiza todos os arquivos onde outros arquivos com extensão diferente ainda não existem

1

Eu quero usar o comando find, para encontrar todos os arquivos com uma certa extensão (avi), onde o mesmo nome de arquivo com outra extensão (mp4) ainda não existe.

considerando esses arquivos:

a.avi
a.mp4
c.avi

só deve resultar no arquivo c.avi sendo encontrado.

    
por clamp 20.04.2014 / 18:57

4 respostas

1

Isso aconteceria?

find . -name '*.avi' -type f -execdir bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {} \; -print

Vou tentar explicar como funciona.

Bem, na verdade, é muito fácil: encontrar todos os arquivos no diretório atual, de forma que o nome tenha avi extension. Para cada um deles, digamos que seja o arquivo X.avi execute no diretório que está em ( execdir ) o comando:

bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {}

onde {} é substituído pelo nome do arquivo, em nosso caso de teste X.avi . Então isso é como

bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' X.avi

Neste ponto, deixe-me enfatizar que isso é 100% seguro em relação a espaços e outros símbolos engraçados em nomes de arquivos! Agora você vê o trecho que o bash executará? Quero dizer este trecho

f=("${0%avi}"*);((${#f[@]}==1))

Ele será executado com o 0-ésimo parâmetro posicional definido para o nosso nome de arquivo; no nosso exemplo de teste é X.avi .

A parte "${0%avi}" expande para o nome do arquivo, com% avi removido (btw, esse nome de arquivo tem a garantia de ter essa extensão neste ponto) e a parte "${0%avi}"* será expandida para todos os arquivos no diretório atual (lembre-se, aquele que contém o arquivo) que tem a extensão .avi . No nosso exemplo de teste, isso é exatamente como:

X.*

Em seguida, criamos uma matriz f desses e, finalmente, saímos desse processo bash com êxito se f contiver apenas um elemento (por isso, muito provavelmente, f contém apenas X.avi em nosso exemplo de teste) e falha de outra forma. Se isso foi um sucesso, nós imprimimos o nome do arquivo.

    
por 20.04.2014 / 20:21
1

Uma solução com 2 exec () s:

find . -name '*.avi' -print | \
  perl -n -e '$x = $_; $x =~ s/\.avi\s*$/.mp4/; (-e $x) || print'

Etapas:

  1. estes são os dróides que você está procurando
  2. para cada linha / arquivo de entrada, testar um arquivo .mp4 correspondente e exibir o nome do arquivo .avi se não for encontrado
    1. copie a linha de entrada para $ x
    2. substitua .mp4 por .avi em $ x (mas apenas no final da linha)
    3. se o arquivo .mp4 correspondente existir, terminamos com essa linha, caso contrário, imprima a linha de entrada
por 21.04.2014 / 02:11
0

Outra opção: encontre todos os arquivos .mp4 e .avi , elimine da lista todos os arquivos para os quais ambas as extensões existem e, em seguida, elimine os arquivos .mp4 restantes:

find . -name '*.avi' -or -name '*.mp4' |
rev | sort -t. -k2 -k1,1 | uniq -s3 -u | grep -v '^4pm' | rev | sort

(assume que nenhum arquivo tem uma nova linha em seu nome).

    
por 22.04.2014 / 01:18
-1

Uma solução com 3 exec () s:

find . -name '*.avi' -print | \
  sed 's/\(.*\)\.avi$/if [ ! -f ".mp4" ]; then echo ".avi"; fi/' | \
  sh

Etapas:

  1. estes são os dróides que você está procurando
  2. retira a extensão de arquivo .avi; gravar um fluxo de comandos sh que testa um arquivo .mp4 correspondente e ecoa o nome do arquivo .avi se não for encontrado
  3. avalie os comandos sh
por 20.04.2014 / 22:49