BRT - Bulk Renaming Tool
Publicado por Pedro Fernandes (última atualização em 25/03/2024)
[ Hits: 1.499 ]
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
Exemplo de manipulação de arquivos
Justificador de texto em 80 colunas
Manipulação de arquivos CSV - Estruturado
Programa para inversão de colunas
Organizador de filmes para o IMDB
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
Como atualizar o Debian 8 para o 10 (10)
Dica sobre iptables ACCEPT e DROP (6)
NGNIX - Aplicar SNAT para evitar roteamento assimetrico (29)
[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