Renomeador Automático de Arquivos de Mídia
Publicado por Felipe Rafailov 15/07/2009
[ Hits: 6.617 ]
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
Compartilhe a conexão por Wi-Fi
Script simple backup em Fita DAT
Script Shell para Administração e Configuração do Samba em Red-Hat / Fedora
Script para conversao de video compativel com PS3
Cirurgia para acelerar o openSUSE em HD externo via USB
Void Server como Domain Control
Modo Simples de Baixar e Usar o bash-completion
Monitorando o Preço do Bitcoin ou sua Cripto Favorita em Tempo Real com um Widget Flutuante
Atualizar Linux Mint 22.2 para 22.3 beta
Jogar games da Battle.net no Linux com Faugus Launcher
Como fazer a Instalação de aplicativos para acesso remoto ao Linux
Conky, alerta de temperatura alta (10)
Assisti Avatar 3: Fogo e Cinzas (3)
Duas Pasta Pessoal Aparecendo no Ubuntu 24.04.3 LTS (42)









