BRT - Bulk Renaming Tool
Publicado por Pedro Fernandes (última atualização em 25/03/2024)
[ Hits: 1.810 ]
Homepage: https://github.com/PedroF37
Projeto em C de um utilitário de renomeação em massa de arquivos pela linha de comando. Pode inserir antes do nome, adicionar depois de string alvo no nome, substituir antigo por novo e deletar sub string em nome de arquivo.
Programa usa recursividade, então varre o diretório alvo e os seus subdiretórios e renomeia todos os arquivos alvo. Programa também permite executar todas as operações filtrando pela extensão do arquivo, então, as operações são executadas nos nomes de arquivos que correspondem com o alvo, mas apenas os que têm a extensão indicada.
Códigos fontes, um Makefile e restantes instruções, assim como exemplos de uso estão no repositório do projeto:
https://github.com/PedroF37/BRT
Grato!
Arquivos brt.c e brt.h:
#include "brt.h"
#include "helper.h"
#include "args.h"
#define ARG_MIN 5
#define ARG_MAX 7
int main(int argc, char **argv)
{
if (argc < ARG_MIN || argc > ARG_MAX)
{
print_usage();
return(EXIT_FAILURE);
}
if (!is_valid_directory(*(argv + 1)))
{
fprintf(stderr, "Diretório %s é inválido ou"
" você não tem permissões\n", *(argv + 1));
return(EXIT_FAILURE);
}
argv++;
map_operation(argc - 3, argv);
return(EXIT_SUCCESS);
}
#ifndef _BRT_H
#define _BRT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <libgen.h>
#include <fileutils.h>
#include <dirutils.h>
#include <strutils.h>
#endif
/****************************************************************************************************************************************/
Arquivos args.c e args.h
#include "brt.h"
#include "args.h"
#include "helper.h"
void number_args(int argc, int args)
{
if (argc != args)
{
print_usage();
exit(EXIT_FAILURE);
}
return;
}
void map_operation(int argc, char **argv)
{
Operation operation;
char *directory = *argv++;
char *operation_str = *argv++;
remove_last_char(directory, '/');
if (strcmp(operation_str, "-a") == 0 ||
strcmp(operation_str, "--add") == 0)
{
number_args(argc, 2);
operation = ADD;
}
else if (strcmp(operation_str, "-i") == 0 ||
strcmp(operation_str, "--insert") == 0)
{
number_args(argc, 2);
operation = INSERT;
}
else if (strcmp(operation_str, "-ae") == 0 ||
strcmp(operation_str, "--add-ext") == 0)
{
number_args(argc, 3);
operation = ADD_EXT;
}
else if (strcmp(operation_str, "-ie") == 0 ||
strcmp(operation_str, "--insert-ext") == 0)
{
number_args(argc, 3);
operation = INSERT_EXT;
}
else if (strcmp(operation_str, "-r") == 0 ||
strcmp(operation_str, "--replace") == 0)
{
number_args(argc, 3);
operation = REPLACE;
}
else if (strcmp(operation_str, "-re") == 0 ||
strcmp(operation_str, "--replace-ext") == 0)
{
number_args(argc, 4);
operation = REPLACE_EXT;
}
else if (strcmp(operation_str, "-d") == 0 ||
strcmp(operation_str, "--delete") == 0)
{
number_args(argc, 2);
operation = DELETE;
}
else if (strcmp(operation_str, "-de") == 0 ||
strcmp(operation_str, "--delete-ext") == 0)
{
number_args(argc, 3);
operation = DELETE_EXT;
}
else
{
print_usage();
exit(EXIT_FAILURE);
}
search_directory(operation, directory, argv);
}
#ifndef _ARGS_H
#define _ARGS_H
/* A operação de renomeação */
typedef enum OperationType
{
ADD, INSERT, ADD_EXT,
INSERT_EXT, REPLACE,
REPLACE_EXT, DELETE,
DELETE_EXT
}
Operation;
/* Cuida de garantir o número certo de argumentos */
void number_args(int argc, int args);
/* Cuida de mapear a operação a ser executada */
void map_operation(int argc, char **argv);
#endif
/*****************************************************************************************************************************/
Arquivos helper.c e helper.h
#include "brt.h"
#include "helper.h"
void print_usage()
{
printf("\nBulk Renaming Tool - Renomeação em Massa de Arquivos\n\n"
"Uso: brt Diretório OPÇÃO ALVO\n\n"
"OPÇÕES:\n"
" -a, --add Alvo Adicionar\n"
" -i, --insert Alvo Inserir\n"
" -ae, --add-ext Alvo Adicionar Extensão\n"
" -ie, --insert-ext Alvo Inserir Extensão\n"
" -r, --replace Alvo Antigo Novo\n"
" -re, --replace-ext Alvo Antigo Novo Extensão\n"
" -d, --delete Alvo Deletar\n"
" -de, --delete-ext Alvo Deletar Extensão\n\n"
"Todas as operações executadas são feitas usando recursão no diretório alvo\n\n"
"Exemplos:\n\n"
" $ brt /home/usuario/Documentos -a curriculum -profissional\n"
" Adiciona '-profissional' depois de 'curriculum', a todos os arquivos em Documentos com 'curriculum' no nome\n"
" $ brt ~/Imagens -i Férias-de-Verão Minhas-\n"
" Insere antes de 'Férias-de-Verão' 'Minhas-' em todos os arquivos em Imagens com 'Férias-de-Verão' no nome\n"
" $ brt ~/Videos --add-ext Aniversário -2023 mp4\n"
" Adiciona '-2023' depois de 'Aniversário' em todos os arquivos em Videos com 'Aniversário' no nome, mas apenas os que têm a extensão 'mp4'\n"
" $ brt ~/Videos -ie Aniversário Minha-Festa-de- mkv\n"
" Insere antes de 'Aniversário' 'Minha-Festa-de-' em todos os arquivos em Videos com 'Aniversário' no nome, mas apenas os que têm a extensão 'mkv'\n"
" $ brt /home/usuario/Imagens --replace Natal _2021 _2022\n"
" Substitui em Imagens '_2021' por '_2022' em todos os arquivos com 'Natal' no nome\n"
" $ brt ~/Imagens -re Natal _2021 _2022 jpg\n"
" Sustitui em Imagens '_2021' por '_2022' em todos os arquivos com 'Natal' no nome, mas apenas os que têm a extensão 'jpg'\n"
" $ brt ~/Documentos -d curriculum -profissional\n"
" Deleta em Documentos '-profissional' em todos os arquivos com 'curriculum' no nome\n"
" $ brt ~/Documentos --delete-ext curriculum -profissional docx\n"
" Deleta em Documentos '-profissional' em todos os arquivos com 'curriculum' no nome mas apenas os que têm a extensão 'docx'\n\n");
return;
}
bool is_renamed(char *pathname, char *new_name)
{
if (rename(pathname, new_name) != 0)
{
return(false);
}
return(true);
}
bool has_same_extension(char *pathname, char *extension)
{
char *ext;
if ((ext = has_extension(pathname)) == NULL)
{
return(false);
}
if (strcmp(ext, extension) != 0)
{
return(false);
}
return(true);
}
char *remove_dot_from_extension(char *extension)
{
char *new_ext;
if ((new_ext = strrchr(extension, '.')) != NULL)
{
return(new_ext + 1);
}
return(extension);
}
Result call_operation(Operation operation,
char *pathname, char **argv)
{
Result result;
char *ext = NULL;
switch (operation)
{
case ADD:
result = add_in_filename(pathname,
*argv, *(argv + 1));
break;
case INSERT:
result = insert_in_filename(pathname,
*(argv + 1));
break;
case ADD_EXT:
ext = remove_dot_from_extension(*(argv + 2));
result = add_in_filename_ext(pathname,
*argv, *(argv + 1), ext);
break;
case INSERT_EXT:
ext = remove_dot_from_extension(*(argv + 2));
result = insert_in_filename_ext(pathname,
*(argv + 1) ,ext);
break;
case REPLACE:
result = replace_in_filename(pathname,
*(argv + 1), *(argv + 2));
break;
case REPLACE_EXT:
ext = remove_dot_from_extension(*(argv + 3));
result = replace_in_filename_ext(pathname,
*(argv + 1), *(argv + 2), ext);
break;
case DELETE:
result = delete_in_filename(pathname,
*(argv + 1));
break;
case DELETE_EXT:
ext = remove_dot_from_extension(*(argv + 2));
result = delete_in_filename_ext(pathname,
*(argv + 1), ext);
break;
}
return(result);
}
void search_directory(Operation operation,
char *directory, char **argv)
{
DIR *dhandle;
if ((dhandle = opendir(directory)) == NULL)
{
fprintf(stderr, "Erro abrindo %s\n", directory);
closedir(dhandle);
exit(EXIT_FAILURE);
}
struct dirent *entry;
Result result;
while ((entry = readdir(dhandle)) != NULL)
{
char *fullpath;
if ((fullpath = create_pathname(directory,
entry->d_name)) == NULL)
{
fprintf(stderr, "Erro criando"
" caminho para %s\n", entry->d_name);
closedir(dhandle);
exit(EXIT_FAILURE);
}
if (is_dot_directory(entry->d_name) ||
is_simlink(fullpath))
{
continue;
}
if (is_directory(fullpath))
{
remove_last_char(fullpath, '/');
search_directory(operation, fullpath, argv);
}
if (is_equal_name(basename(fullpath), *argv) == false)
{
continue;
}
if ((result = call_operation(operation,
fullpath, argv)) != SUCCESS)
{
if (result == CONTINUE)
{
continue;
}
else
{
closedir(dhandle);
exit(EXIT_FAILURE);
}
}
free(fullpath);
}
closedir(dhandle);
}
#ifndef _HELPER_H
#define _HELPER_H
#include "operations.h"
#include "args.h"
/* Cuida de mostrar como usar o programa */
void print_usage();
/* Renomeia e retorna true ou false
* para se foi ou não renomeado */
bool is_renamed(char *pathname, char *new_name);
/* Cuida de verificar que se tem extensão e se são iguais */
bool has_same_extension(char *pathname, char *extension);
/* Cuida de remover o . de ".pdf", etc, caso tenha digitado . */
char *remove_dot_from_extension(char *extension);
/* Cuida de chamar a operação apropriada */
Result call_operation(Operation operation,
char *pathname, char **argv);
/* Cuida de varrer o diretório alvo recursivamente */
void search_directory(Operation operation,
char *directory, char **argv);
#endif
/**************************************************************************************************************/
Arquivos operations.c e operations.h
#include "brt.h"
#include "operations.h"
#include "helper.h"
Result add_in_filename(char *pathname,
char *target, char *addition)
{
char *new_name;
if ((new_name = str_insert(pathname,
target, addition)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname,
new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
Result insert_in_filename(char *pathname, char *insert)
{
char *new_name;
if ((new_name = insert_in_beginning(basename(
pathname), insert)) == NULL)
{
return(FAILURE);
}
char *pathname_copy = duplicate(pathname);
if (pathname_copy == NULL)
{
free(new_name);
return(FAILURE);
}
char *full_new_name;
if ((full_new_name = create_pathname(
dirname(pathname_copy), new_name)) == NULL)
{
free(pathname_copy);
free(new_name);
return(FAILURE);
}
if (is_renamed(pathname,
full_new_name) == false)
{
free(pathname_copy);
free(full_new_name);
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, full_new_name);
free(pathname_copy);
free(full_new_name);
free(new_name);
return(SUCCESS);
}
Result add_in_filename_ext(char *pathname,
char *target, char *addition, char *extension)
{
if (has_same_extension(pathname,
extension) == false)
{
return(CONTINUE);
}
char *new_name;
if ((new_name = str_insert(pathname,
target, addition)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname, new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
Result insert_in_filename_ext(char *pathname,
char *insert, char *extension)
{
if (has_same_extension(pathname,
extension) == false)
{
return(CONTINUE);
}
char *new_name;
if ((new_name = insert_in_beginning(
basename(pathname), insert)) == NULL)
{
return(FAILURE);
}
char *pathname_copy = duplicate(pathname);
if (pathname_copy == NULL)
{
free(new_name);
return(FAILURE);
}
char *full_new_name;
if ((full_new_name = create_pathname(
dirname(pathname_copy), new_name)) == NULL)
{
free(pathname_copy);
free(new_name);
return(FAILURE);
}
if (is_renamed(pathname,
full_new_name) == false)
{
free(pathname_copy);
free(full_new_name);
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, full_new_name);
free(pathname_copy);
free(full_new_name);
free(new_name);
return(SUCCESS);
}
Result replace_in_filename(char *pathname,
char *old_str, char *new_str)
{
char *new_name;
if ((new_name = str_replace(pathname,
old_str, new_str)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname, new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
Result replace_in_filename_ext(char *pathname,
char *old_str, char *new_str, char *extension)
{
if (has_same_extension(pathname,
extension) == false)
{
return(CONTINUE);
}
char *new_name;
if ((new_name = str_replace(pathname,
old_str, new_str)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname, new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
Result delete_in_filename(char *pathname, char *to_delete)
{
char *new_name;
if ((new_name = str_remove(pathname,
to_delete)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname, new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
Result delete_in_filename_ext(char *pathname,
char *to_delete, char *extension)
{
if (has_same_extension(pathname,
extension) == false)
{
return(CONTINUE);
}
char *new_name;
if ((new_name = str_remove(pathname,
to_delete)) == NULL)
{
return(FAILURE);
}
if (is_renamed(pathname, new_name) == false)
{
free(new_name);
return(FAILURE);
}
printf("%s -->> %s\n", pathname, new_name);
free(new_name);
return(SUCCESS);
}
#ifndef _OPERATIONS_H
#define _OPERATIONS_H
/* O resultado da operação escolhida */
typedef enum OperationResult
{
SUCCESS, CONTINUE, FAILURE
}
Result;
/* Cuida de adicionar no nome depois de target */
Result add_in_filename(char *pathname, char *target, char *addition);
/* Cuida de inserir no nome antes de target */
Result insert_in_filename(char *pathname, char *insert);
/* Cuida de adicionar no nome depois de target, filtrando por extensão*/
Result add_in_filename_ext(char *pathname, char *target,
char *addition, char *extension);
/* Cuida de inserir no nome antes de target, filtrando por extensão*/
Result insert_in_filename_ext(char *pathname,
char *insert, char *extension);
/* Cuida de substituir old_str por new_str nos
* arquivos com target no nome */
Result replace_in_filename(char *pathname,
char *old_str, char *new_str);
/* Cuida de substituir old_str por new_str nos
* arquivos com target no nome, filtrando por extensão*/
Result replace_in_filename_ext(char *pathname,
char *old_str, char *new_str, char *extension);
/* Cuida de deletar to_delete nos arquivos com target no nome */
Result delete_in_filename(char *pathname, char *to_delete);
/* Cuida de deletar to_delete nos arquivos com
* target no nome, filtrando por extensão*/
Result delete_in_filename_ext(char *pathname,
char *to_delete, char *extension);
#endif
Agenda (fones, compromissos, aniversários) em C usando arquivos binários
Leitura de arquivo texto separando as colunas
MakeInt - gerador de wordlist numérica
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?









