Renomeador Automático de Arquivos de Mídia
Publicado por Felipe Rafailov 15/07/2009
[ Hits: 6.247 ]
Este script foi criado para renomear arquivos de mídia, como Vídeos e Fotos, porém pode ser utilizado com qualquer tipo de arquivo. É um script bem completo que aceita uma grande variedade de opções de linha de comando.
Para visualizar o resultado sem afetar os arquivos e/ou diretórios, utilize a opção --dummy. Importante usar esta opção para saber como ficariam os arquivos após as transações. Mais informações, incluindo um manual completo com exemplos, pode ser encontrado aqui:
http://maisena.net/scripts/nconv/
#!/bin/bash # Desenvolvido por Felipe Rafailov # E-Mail e GTalk: felipe.rafailov@gmail.com # Quantos diretórios o script irá criar # 0 - Não cria nenhum diretório (ex. Lost S01E01.avi) # 1 - Cria um diretório para o seriado (ex. Lost/S01E01.avi) # 2 - Cria diretórios para o seriado e a temporada (ex. Lost/S01/01.avi) # 3 - Cria um diretório para cada episódio (ex. Lost/S01/S01E01/S01E01.avi) DIRLEVEL=1 #DIRLEVEL=0 # Separador usado para o nome do arquivo e/ou diretório EOW=' ' #EOW='.' #EOW='_' # Cria os diretórios (se necessário) e move o arquivo # 0 - Somente exibe o nome na tela (para visualizar) # 1 - Efetua a transação, movendo o arquivo (padrão) MOVE=1 # Quando habilitado, efetua a cópia do arquivo original para seu novo # destino. COPY=0 # Habilita o modo verboso # 0 - Desabilitado (padrão) # 1 - Habilitado VERBOSE=0 # No modo interativo, em cada alteração o usuário pode aceitar a sugestão, # rejeitar, ou propor outro nome para o arquivo. INTERACTIVE=0 # Os arquivos a serem movidos são armazenados nesta variável FILES= # Quando habilitado, o nome completo será atribuído ao arquivo. # Senão, somente a parte referente ao número do episódio é colocado. # 0 - Nomes curtos, ex.: S01E01.avi # 1 - Nomes compridos, ex.: Lost S01E01.avi FULLNAME=1 # Permite especificar o diretório de saída, onde os arquivos serão # criados. Por padrão, usa-se o diretório atual. #OUTPUT=$PWD OUTPUT= # Permite adicionar um nome (inicial) a todos os arquivos alterados. # Permite também adicionar um contador ao nome, utilizando o caracter # especial '%' BASENAME= COUNT=0 # Esta variável contém uma lista, separada por vírgulas, de todos os termos # a serem ignorados no nome do arquivo. Outra opção, --ignoreall, permite # ignorar completamente o nome original do arquivo. O novo nome será formado # pelo valor de --basedir e --basename. IGNORE= IGNOREALL=0 # Contém o nome do arquivo usado como fonte dos nomes dos episódios, # quando o parâmetro --source é utilizado. O arquivo deve possuir uma # estrutura específica, ex.: # S01E01 Nome do Episódio 1 da 1a temporada SOURCE= # Função responsável por unir duas strings, utilizada para anexara # duas strings consecutivamente, separadas por um caractere ou string # append(){ if [ -n "$1" ]; then if [[ $1 =~ $2$ ]]; then echo "$1" else echo "${1}${3}${2}" fi else echo "$2" fi } # Coloca a primeira palavra em Caixa Alta, quando necessário capitalize(){ if [ ${#1} -ge 3 ] || [[ "$2" =~ ^$1 ]]; then part1="$(echo -n "${1:0:1}" | tr "[:lower:]" "[:upper:]")" part2="$(echo -n "${1:1}" | tr "[:upper:]" "[:lower:]")" echo "${part1}${part2}" else echo "$(echo "$1" | tr "[:upper:]" "[:lower:]")" fi } # Esta função substitui o caractere especial '%' por um contador. Esta função é # utilizada para interpretar o argumento da opção --basename e, no modo # interativo, também a opção de escolher o nome do arquivo manualmente. replace_counter() { NEWCOUNT=$COUNT if [ -n "$1" ] && [[ $1 =~ '(\*?%+)' ]]; then t_mask="${BASH_REMATCH[1]}" if [ "${t_mask:0:1}" = "*" ]; then if [ $INTERACTIVE -eq 1 ]; then NEWCOUNT=1 fi t_mask="${t_mask:1}" else NEWCOUNT=$(($NEWCOUNT+1)) fi t_count=$NEWCOUNT while [ ${#t_count} -lt ${#t_mask} ]; do t_count="0$t_count" done NEWNAME="$(echo "$1" | sed "s/*\?$t_mask/$t_count/")" else NEWNAME="$1" fi echo "NEWNAME=\"$NEWNAME\"" echo "NEWCOUNT=$NEWCOUNT" } show_help(){ echo "Uso: $(basename $0) [-i] [-d] '.' [-l] 3 arquivo1.avi arquivo2.avi ... -h --help Mostra informações resumidas sobre o uso do programa e sai. -v --verbose Mostra informações adicionais na saída, informando o usuário sobre o estado atual da execução. --dummy Mostra as operações que serão realizadas, porém não efetua nenhuma mudança no disco rígido. Também implica em -v. -s --short Utiliza nomes curtos para os arquivos. -c --copy Copia o arquivo original para seu novo destino, em vez de movê-lo. Útil para quando os arquivos originais estiverem em mídias de somente-leitura (CD's ou DVD's). -i --interactive Habilita o modo interativo, que permite visualizar as alterações a serem realizadas no disco rígido antes de aceitá-las. --ignore a,b,c Permite especificar uma lista (separada por vírgulas) de termos que não serão consideradas como parte do novo nome do arquivo. Esta opção não distingue maiúsculas/minúsculas. --ignoreall Ignora completamente o nome original do arquivo. O novo nome deverá ser baseado nos valores de --basename e --basedir. -d --delimiter d Altera o caractere delimitador. Por padrão, usa-se espaço. --basename n Permite adicionar um nome ao início de cada arquivo a ser alterado. Você pode acicionar um contador com o caractere '%'. Usando-o múltiplas vezes seguidas permite adicionar mais dígitos ao contador. Ex.: --basename '%%' = 01, --basename '%%%' = 001, etc. --basedir n Permite especificar o diretório de base onde os novos diretórios e arquivos serão criados. --source file Esta opção permite especificar um arquivo para servir de fonte para os nomes dos episódios. O arquivo deve possuir o seguinte formato: S01E01 Nome do Episódio 1 da 1a Temporada -l --level l Altera o número de sub-diretórios que serão criados. Aceita valores de 0-3. O padrão é 1. Por exemplo: nível 0: Lost S01E01.avi nível 1: Lost/Lost S01E01.avi nível 2: Lost/S01/Lost S01E01.avi nível 3: Lost/S01/S01E01/Lost S01E01.avi" } # Faz a leitura das opções de linha de comando do script while [ -n "$1" ]; do case "$1" in -h | --help) show_help exit 0 ;; -v | --verbose) VERBOSE=1 ;; -i | --interactive) MV_OPTS="-i" INTERACTIVE=1 ;; --dummy) MOVE=0 VERBOSE=1 ;; -s | --short) FULLNAME=0 ;; -c | --copy) COPY=1 ;; -d | --delimiter) shift if [ "$1" = '/' ]; then echo ERRO: Delimitador inválido exit 1 fi EOW="$1" ;; --basedir) shift # Não é necessário verificar o diretório de saída, isso é feito mais adiante OUTPUT="$(echo $1 | sed 's/\/$//')" ;; --basename) shift BASENAME="$1" ;; --source) shift if [ -f "$1" ] && [ -r "$1" ]; then SOURCE="$1" else echo "AVISO: Não pode ler do arquivo de fonte $1" fi ;; --ignore) shift IGNORE=",$(echo "$1" | sed 's/[[:space:]]\+/,/g')," ;; --ignoreall) IGNOREALL=1 ;; -l | --level) shift if [[ $1 =~ ^[[:digit:]]+$ ]] && [ $1 -ge 0 ] && [ $1 -le 3 ]; then DIRLEVEL=$1 else echo "ERRO: Nível inválido. Utilize valores de 0 a 3." echo "Veja $(basename $0) --help para maiores informações." exit 1 fi ;; *) FILES=$(append "$FILES" "$1" \;) ;; esac shift done # Verifica se foram passados arquivos como parâmetro if [ -z "$FILES" ]; then echo ERRO: Nenhum arquivo fornecido para renomear exit 1 fi # Caso alguma das opções, --basedir ou --basename for usada, faz # o tratamento do nome, como espaços. if [ -n "$OUTPUT" ]; then OUTPUT="$(echo $OUTPUT | sed "s/[[:space:]]\+/${EOW}/g")" fi if [ -n "$BASENAME" ]; then BASENAME="$(echo $BASENAME | sed "s/[[:space:]]\+/${EOW}/g")" fi # A variável IFS é alterada pois no caso da variável FILES, os arquivos # são separados por ponto-e-vírgula ';' IFS=';' for file in $FILES; do # O nível de expansão pode variar conforme o nome do arquivo. Caso não seja # encontrado um número de episódio, um nível inferior (1) é usado. t_dirlevel=$DIRLEVEL t_short=$FULLNAME t_basename="$BASENAME" # Pula arquivos não existentes e diretórios (quando não estiver usando --dummy) if [ -d "$file" ] || [ $MOVE -eq 1 ] && [ ! -f "$file" ]; then if [ -d "$file" ]; then echo "ERRO: \"$file\" é um diretório." elif [ ! -f "$file" ]; then echo "ERRO: Arquivo não encontrado: \"$file\"" fi continue fi # Verifica o diretório de saída (quando especificado) ou o diretório atual if [ -n "$OUTPUT" ]; then t_ckdir="$OUTPUT" else t_ckdir=$PWD fi while [ ! -d $t_ckdir ]; do t_ckdir="$(dirname "$t_ckdir")" done if [ ! -w "${t_ckdir}" ] && [ $MOVE -eq 1 ]; then echo "ERRO: Não posso criar arquivo(s)/diretório(s) de saída em $t_ckdir" exit 1 fi t_filename="$(basename "$file")" t_extension="$(echo $t_filename | awk -F . '{print $NF}')" # Verifica se o arquivo possui extensão if [ "$t_filename" = "$t_extension" ]; then unset t_extension else t_extension=".$t_extension" fi if [ $IGNOREALL -eq 0 ]; then t_filename=$(basename "$file" "$t_extension" | sed 's/[[:punct:]]\+/ /g') else unset t_filename fi unset IFS for t_part in $t_filename ; do # Remove partes indesejadas do nome do arquivo, passadas pelo argumento # --ignore t_check="$(echo "$t_part" | sed "s/[[:digit:]]/%/g")" if [ -n "$(echo $IGNORE | grep -i ",$t_check,")" ] || [ -n "$(echo $IGNORE | grep -i ",$t_part,")" ]; then continue # Procura pelo descritivo do número do episódio, geralmente # SXXEYY, onde XX é a temporada e YY é o número do episódio. # Ex.: S01E01 elif [[ $t_part =~ ^[sS]?[[:digit:]]+[eE]?[[:digit:]]*$ ]]; then filename="$(append "$filename" "$(echo $t_part | tr se SE)" "$EOW")" break # Caso seja um nome composto alfanumérico, do tipo arquivo01 elif [[ $t_part =~ ^([[:alpha:]]+)([[:digit:]]+)$ ]]; then t_alpha_part="${BASH_REMATCH[1]}" t_numeric_part="${BASH_REMATCH[2]}" t_check="$(echo "$t_numeric_part" | sed "s/[[:digit:]]/%/g")" if [ -n "$(echo $IGNORE | grep -i ",$t_alpha_part,")" ] || [ -n "$(echo $IGNORE | grep -i ",$t_check,")" ] || [ -n "$(echo $IGNORE | grep -i ",$t_numeric_part,")" ]; then continue else t_part="$(capitalize "$t_alpha_part" "$t_filename")" dirname="$(append "$dirname" "$t_part" "$EOW")" filename="$(append "$filename" "$t_numeric_part" "$EOW")" fi else t_part="$(capitalize "$t_part" "$t_filename")" dirname="$(append "$dirname" "$t_part" "$EOW")" fi done # Quando o nome do diretório for vazio, altera o t_dirlevel para # compensar a falta do nome if [ -z "$dirname" ] && [ -n "$filename" ]; then if [ $t_dirlevel -eq 1 ]; then t_dirlevel=2 elif [ $t_dirlevel -eq 2 ]; then t_dirlevel=3 fi fi # Caso o nome do arquivo (filename) esteja vazio, este recebe o nome do # diretório if [ -z "$filename" ] && [ -n "$dirname" ]; then filename="$dirname" if [ $t_dirlevel -gt 1 ]; then t_dirlevel=1 fi fi # Altera o nome entre o nome curto e longo, de acordo com a # opção --short. Também verifica se o nome do diretório e do arquivo # são iguais, para evitar nomes repetidos. if [ $t_short -eq 1 ] && [ ! "$dirname" = "$filename" ]; then t_fullname="$(append "$dirname" "$filename" "$EOW")" else t_fullname=$filename fi # Caso exista um prefixo (--basename), verificar a existencia do # caracter de contador e substituí-lo pelo número do contador eval "$(replace_counter "$t_basename")" t_basename="$NEWNAME" COUNT=$NEWCOUNT # Adiciona um prefixo a todos os arquivos alterados (usando a opção --basename) t_fullname="$(append "$t_basename" "$t_fullname" "$EOW")" # Quando estiver usando a opção --source, obter o nome do episódio através do # arquivo de fonte especificado pelo parâmetro, tratar a entrada e anexar este # no nome do arquivo. if [ -n "$SOURCE" ] && [[ $filename =~ ^S?[[:digit:]]+E?[[:digit:]]*$ ]]; then t_episode="$(cat "$SOURCE" | grep "$filename" | cut -d' ' -f2- | sed "s/[[:space:]]\+/${EOW}/g")" t_fullname="$(append "$t_fullname" "$t_episode" "$EOW")" fi # Verifica se o nome do arquivo é vazio. Caso seja, significa que o script falhou # em determinar o nome do arquivo, logo ele será ignorado if [ -z "$t_fullname" ]; then echo "ERRO: Falha ao determinar nome do arquivo. Pulando arquivo $file" continue else # Adiciona a extensão do arquivo no nome completo t_extension="$(echo $t_extension | tr "[[:upper:]]" "[[:lower:]]")" t_fullname="$(append "$t_fullname" "$t_extension")" fi # Caso o DIRLEVEL seja maior ou igual a 2, o seguinte código descobre o nome do # diretório intermediário, que é formado pelos primeiros dígitos numéricos do # código do episódio, ou, no caso de somente haver números, usa-se a dezena ou # centena. # Ex.: # S01E01 => S01 # 115 => 100 if [ $t_dirlevel -ge 2 ] && [[ $filename =~ ^(S?[[:digit:]]+) ]]; then t_midname=${BASH_REMATCH[1]} if [ ! "${t_midname:0:1}" = "S" ]; then t_size=${#t_midname} if [ $t_size -le 2 ]; then if [ $t_size -eq 1 ]; then t_midname="$(append "0" "$t_midname")" fi t_size=1 else t_size=$(expr ${#t_midname} - 2) fi t_xpon=$((10**$t_size)) t_midname=$(expr $t_midname - $(expr $t_midname % $t_xpon)) fi fi # Estabelece o nível de diretórios de acordo com a variável # DIRLEVEL (t_dirlevel) case $t_dirlevel in 0) newname="$t_fullname" ;; 1) newname="$(append "$dirname" "$t_fullname" \/)" ;; 2) filename="$(append "$t_midname" "$t_fullname" \/)" newname="$(append "$dirname" "$filename" \/)" ;; 3) filename="$(append "$t_midname" "$filename" \/)" filename="$(append "$filename" "$t_fullname" \/)" newname="$(append "$dirname" "$filename" \/)" ;; esac # Permite adicionar um diretório de saída usando a opção --basedir newname="$(append "$OUTPUT" "$newname" \/)" # Se no modo interativo, permite ao usuário aceitar o nome, rejeitar, # ou propor um nome próprio. O usuário também pode cancelar o modo # iterativo e sair do programa. t_exit=0 t_skip=0 while [ $INTERACTIVE -eq 1 ] && [ $t_exit -eq 0 ]; do echo if [ $COPY -eq 1 ]; then t_action=Copiar else t_action=Mover fi echo $t_action \"$file\" \=\> \"$newname\" echo -n "Escolha uma opção, ou ? para ajuda: " read t_option while [[ ! $t_option =~ ^[12345?arpcsARPCS]$ ]]; do echo "Opção Inválida: $t_option" read t_option done case $t_option in a | A | 1) t_exit=1 ;; r | R | 2) unset dirname unset filename IFS=';' t_exit=1 t_skip=1 ;; p | P | 3) echo -n "Digite o nome do arquivo: " read t_newname while [ -z "$t_newname" ]; do echo -n "Digite o nome do arquivo: " read t_newname done eval "$(replace_counter "$t_newname")" newname="$(echo $NEWNAME | sed "s/[[:space:]]\+/${EOW}/g")" COUNT=$NEWCOUNT t_exit=1 ;; c | C | 4) INTERACTIVE=0 unset MV_OPTS t_exit=1 ;; s | S | 5) exit 0 ;; ?) echo Opção 1. a Aceitar nome escolhido, alterar nome do arquivo echo Opção 2. r Rejeitar nome escolhido, manter nome original echo Opção 3. p Propor outro nome para o arquivo echo Opção 4. c Cancelar o modo interativo, continuar no automático echo Opção 5. s Sair do programa ;; esac done if [ $t_skip -eq 1 ]; then continue fi t_return=0 # Move/renomeia o arquivo para seu novo destino e cria o diretório caso # seja necessário if [ $MOVE -eq 1 ]; then t_newdir=$(dirname "$newname") if [ ! -d "$t_newdir" ] && [ ! -f "$t_newdir" ]; then mkdir -p "$t_newdir" fi if [ $COPY -eq 1 ]; then t_cmd=cp else t_cmd=mv fi $t_cmd $MV_OPTS "$file" "$newname" t_return=$? fi # Habilita a saída em modo verboso if [ $VERBOSE -eq 1 ]; then [[ $t_return -ne 0 ]] && echo -n "ERRO: " || echo -n "OK: " echo $newname fi # Limpa as variáveis utilizadas unset dirname unset filename IFS=';' done
Redimensionador automático de imagens
Teste compatativo entre discos e/ou partições
Nautilus-script: Edite com o Gimp
tag-mp3 - Um script para editar e/ou visualizar algumas tags ID3 de arquivos MP3
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Efeito "livro" em arquivos PDF
Como resolver o erro no CUPS: Unable to get list of printer drivers
Flatpak: remover runtimes não usados e pacotes
Mudar o gerenciador de login (GDM para SDDM e vice-versa) - parte 2
Inkscape Atualização 1.4 [RESOLVIDO] (8)
samba4 - 4.21 utilizar phpldapadmin [RESOLVIDO] (5)
[Python] Automação de scan de vulnerabilidades
[Python] Script para analise de superficie de ataque
[Shell Script] Novo script para redimensionar, rotacionar, converter e espelhar arquivos de imagem
[Shell Script] Iniciador de DOOM (DSDA-DOOM, Doom Retro ou Woof!)
[Shell Script] Script para adicionar bordas às imagens de uma pasta