Verificando se existe um arquivo em vários diretórios

4

Eu preciso de um script que analise os arquivos em um diretório e veja se ele existe em um dos vários diretórios.

Eu preciso de algo assim:

for files in /downloads/ #may or may not be in a sub-directory
do
   print if file exists in /media/tv, /media/movie, or /media/music
done

os arquivos não estarão na raiz do diretório. Não posso apenas pesquisar / mídia, porque não quero pesquisar em cd-rom ou vídeos.

Estou usando a versão mais recente do servidor Ubuntu.

    
por andrew.vh 13.11.2012 / 06:31

7 respostas

7

Você não menciona se precisa manter os arquivos (talvez removendo duplicatas?), hardlink ou qualquer outra coisa.

Então, dependendo da sua intenção, a melhor solução seria usar um programa como rdfind (não interativo), fdupes (mais interativo, permitindo que você escolha quais arquivos manter ou não), duff (para relatar somente os arquivos duplicados) ou muitos outros.

Se você quiser algo mais sofisticado com uma GUI que permita escolher o que manter por meio de uma interface de apontar e clicar, fslint (através do seu comando fslint-gui ) seria a minha escolha recomendada.

Todos os itens acima estão disponíveis no repositório do Debian e, por transição, eu acho que eles estão nos repositórios do Ubuntu ou do Linux Mint, se é isso que você está usando.

    
por 13.11.2012 / 09:15
4

Isso pode ser muito lento se você percorrer /downloads ou /media para cada nome de arquivo. Portanto, percorra cada hierarquia apenas uma vez, armazene a lista de nomes de arquivos e, em seguida, processe as listas.

Para simplificar, suponho que os nomes dos seus arquivos não contenham novas linhas.

find /downloads -type f | sed 's!^.*/\(.*\)$!/&!' |
  sort -t / -k1,1 >/tmp/downloads.find
find /media/tv /media/music /media/movie -type f |
  sed 's!^.*/\(.*\)$!/&!' |
  sort -t / -k1,1 >/tmp/media.find

Neste ponto, os dois arquivos .find contêm listas de caminhos de arquivos, com o nome do arquivo anexado, classificado por nome de arquivo. Junte os arquivos no primeiro campo / -separated e limpe o resultado um pouco.

join -j 1 -t / /tmp/downloads.find /tmp/media.find |
  sed -e 's![^/]*/!!' -e 's![^/]*/! has the same name as !'
    
por 13.11.2012 / 23:31
1

Aqui está uma implementação no bash usando a expansão de chaves:

the_file=foo.mp3
for file in /downloads/media/{tv,movie,music}/"$the_file"; do 
   if [[ -e $file ]]; then
      printf '%s found in %s:\n' "$the_file" "${file%/*}"
   fi
done
    
por 13.11.2012 / 07:32
1

Isso listará todos os arquivos em downloads que também estão em seus subdiretórios / media especificados:

find /downloads -type f | while IFS= read -r file ; do
    bn=$(basename "$file")
    find /media/tv /media/movie /media/music -type f -name "$bn"
done

e isso apenas imprimirá se o arquivo foi encontrado em um desses / subdiretórios de mídia ou não.

find /downloads -type f | while IFS= read -r file ; do
    bn=$(basename "$file")

    count=$(find /media/tv /media/movie /media/music -type f -name "$bn" | wc -l)

    [ "$count" -gt 0 ] && printf "found %s\n" "$f"
done

Se houver muitos arquivos em / downloads, executar find uma vez para cada arquivo será muito lento. Isso pode ser resolvido (se você estiver usando o GNU find ) construindo uma expressão regular contendo todos os nomes de arquivos que você quer procurar e usando as opções find ou -regex do GNU -iregex .

REGEXP="^.*/\("
find /downloads -type f | while IFS= read -r file ; do
    bn=$(basename "$file" | sed -e 's/\./\./g')
    REGEXP="$REGEXP\|$bn"
done
REGEXP="$REGEXP\)$"

find /media/tv /media/movie /media/music -type f -iregex "$REGEXP"

E aqui está outra versão que não usa o shell read embutido, então deve ser muito mais rápido:

REGEXP=$(find /downloads -type f | sed -e 's/^.*\/// ; s/\([]*\ .|[]\)/\/g ; 
    s/$/\|/' | tr -d '\n')
find /media/tv /media/movie /media/music -type f -iregex "^.*\($REGEXP\)$"

Ambas as versões regexp são limitadas pelo comprimento máximo de linha de um comando shell - muitos arquivos e eles falharão.

NOTA: como a maioria das outras respostas aqui, esses exemplos não lidam com nomes de arquivos que possuem novas linhas ( \n ) neles. Qualquer outro personagem, incluindo espaço, está bem.

    
por 06.11.2015 / 10:32
0
echo "Enter file name"
read file
flag=0

for i in 'ls'
do
  if [ $i == $file ] ;then
    echo "File exist"
    flag=1
    break;
  fi
done

if [ $flag == 0 ] ;then
  echo "File not exist"
fi
    
por 08.04.2013 / 18:44
0
chk='/[m]edia'
for f in $chk/movies/file $chk/tv/file $chk/music/file
do  [ -z "${f##"$chk"*}" ] ||
    printf %s\n "$f exists!"
done

Você pode globar um valor conhecido e verificar seus resultados para resolução.

    
por 14.08.2014 / 02:30
0

Que tal:

cd /sourcemp4folder
for i in *.mp4
 do
 a=$(find /destination/ -iname "$i" -print | wc -l)
 if [[ $a > 0 ]]; then echo "Skip "
 else echo "cp $i to /destination/"
 fi
 done
    
por 06.11.2015 / 09:10