Renomeador Automático de Arquivos de Mídia
Publicado por Felipe Rafailov 15/07/2009
[ Hits: 6.549 ]
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
Script para criação de diretorio do usuario no Samba com A.D.
Script para configuração do jogo 0 A.D
Limpar pacotes com versões antigas do cache do apt
Baixando, listando e limpando os pacotes órfãos
IA Turbina o Desktop Linux enquanto distros renovam forças
Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Linux em 2025: Segurança prática para o usuário
Desktop Linux em alta: novos apps, distros e privacidade marcam o sábado
IA chega ao desktop e impulsiona produtividade no mundo Linux
Atualizando o Fedora 42 para 43
Como saber se o seu e-mail já teve a senha vazada?
Como descobrir se a sua senha já foi vazada na internet?
Instalação dualboot Windows 11 e Debian 13 (14)
Ubunto não reconhece rede ethernet (1)









