Shell Script para isolar arquivos espalhados em pastas diferentes

4

Eu preciso escrever um script de shell que percorra uma determinada estrutura de diretórios em vários níveis, reconheça os arquivos de vídeo espalhados nas pastas e copie todos eles para outra única pasta. Os arquivos de vídeo são, na verdade, arquivos de dados do Macromedia Flash (salvos no cache do meu navegador) e não possuem nenhuma extensão em particular, como .MP4 ou .FLV, apenas nomes numéricos.

Agora, consegui começar:

#!/bin/bash
#This script checks if the given folder contains video file and copies them another folder
filePath=$1                 #the argument(The folder Path)
if [[ -z "$filePath" ]]; then  #empty argument check
    echo "Please input the folder to search"
    exit 1
fi
if [ -d "$filePath" ]; then 
 if [ -L "$filePath" ]; then #check if the input folder is a valid folder
  echo "directory $file does not exist"
  exit 1
 fi 
else  #improper input given by the user     
 echo "$filePath is either not a valid directory or it is a file.Please enter a valid directory address" 
 exit 1
fi
find $filePath type -d | \ #the find here list all the files and directories in the given folder
while read i 
do
    if [[ -d "$i" ]]; then
        idDirectory    #Call the function
    elif [[ -f "$i" ]]; then
#check if its the file in the expected format
#do the copy work
    fi
done
exit 0


idDirectory(){ # A recursive function to go multiple levels of the directory tree
    #the function which tells if the path is directory or file
    #If its a directory then it will call itself, till it gets a file
    #need some help here!!!!!
}


Eu preciso escrever a função recursiva que identifica e percorre diretórios.Eu tentei isso . mas não foi bem sucedido.  

    
por Aditya Cherla 13.02.2014 / 19:53

2 respostas

4

Alguns princípios gerais de programação de shell:

  • Sempre coloque aspas duplas em torno das substituições de variáveis (a menos que você saiba que precisa do comportamento sem aspas). "$foo" significa o valor da variável foo , mas $foo das cotas externas sofre processamento adicional .
  • O mesmo vale para substituições de comandos: "$(foo)" .
  • while read i; do … remove espaços em branco iniciais e finais e barras invertidas. Use while IFS= read pr i; do … para linhas de processo exatamente .

find $filePath type -d apenas lista diretórios.

Piping find into while read não é a maneira mais fácil ou robusta de executar um comando shell para cada arquivo. Use a ação -exec em find para processar arquivos de maneira robusta sem problemas com nomes de arquivos que contenham caracteres especiais, como espaço em branco. Se você precisar de mais de um comando, invoque sh ; para processar um arquivo de cada vez:

find … -exec sh -c 'command1 "$0"; command2 "$0"' {} \;

Para acelerar um pouco as coisas, você pode usar um idioma mais complexo que agrupa arquivos para reduzir o número de sucessivas invocações de shell:

find … -exec sh -c 'for x; do command1 "$x"; command2 "$x"; done' _ {} +

Todas as verificações no início do seu script são inúteis ou praticamente inúteis. Você não se importa se o argumento é um link simbólico, por exemplo, e sua mensagem de erro nesse caso está incorreta.

Eu assumo que seu script é chamado com dois argumentos, o diretório de origem e o diretório de destino. Você pode usar mkdir -p para criar diretórios de destino conforme necessário. Isso ajuda a executar find no diretório atual, para evitar a manipulação do nome do arquivo para calcular os caminhos de destino.

Chame file para verificar o tipo de um arquivo com base em seu conteúdo. Você pode querer ajustar os formatos de arquivo aceitos.

cd "$1" || exit
find . -type f -exec sh -c '
  # $0 = target directory; $1 = source file
  case "$(file "$1");" in
    video/x-flv\;*)
      mkdir -p "$0/${1%/*}"    # create target subdirectory if needed
      cp -p "$1" "$0/$1"       # copy the file under the same relative path
  esac
' "$2" {} \;
    
por 13.02.2014 / 22:34
1

Aqui está um script com uma função recursiva, que faz o que você estava procurando:

#!/bin/bash

if [ "$#" -ne 1 ]; then
   echo "usage: "$0" <search_dir>"
   exit 1
fi

# recursive function to walk a directory tree
walktree() {
  # $1 is the function parameter
  local files=$(find "$1" -maxdepth 1 -type f)          # find all files in the current dir

  for file in $files; do                                # iterate through all found files
    if [[ "$(file "$file")" == *video/x-flv* ]]; then   # check the file content
      echo "found one"
      # put your copy code here
    fi
  done

  local subdirs=$(find "$1" -maxdepth 1 -type d)        # find all sub-directories

  for dir in $subdirs; do                               # iterate through all sub-directories
    if [ "$dir" != "$1" ]; then                         # omit the current directory
      walktree "$dir"                                   # call the recursive function
    fi
  done
}

walktree "$1"                                           # first call with <search_dir>

No entanto, eu ainda recomendo que você use apenas find . -type f conforme explicado por Gilles .

    
por 14.02.2014 / 01:11