Trabalhando com Recursividade no MS-DOS
856 visualizações
Pois é, sei que muitas pessoas vão ler este tópico e se perguntar “Para quê eu deveria aprender recursividade no MS-DOS?”
E a resposta seria, os arquivos batch já existem e que por falta de tempo ou de recursos ($) optamos pela alternativa mais rápida e de menor custo.
Nota: hoje em dia, os jovens não devem conhecer a linguagem batch utilizada no MS-DOS, pois já foram introduzidos em um sistema operacional de janelas, vulgo M$. Muitos nem devem saber que é possível programar no MS-DOS mas se pesquisarem mais a fundo, verão que é possível fazer muita coisa com essa linguagem.
Hoje em dia, temos muitas ferramentas de desenvolvimento gratuitas para o nosso propósito e eu não aconselho o uso de arquivos batchs pois são muito vulneráveis por causa do seu código ser aberto.
Como teoria não é facilmente aplicada, vou demonstrar com um exemplo prático abaixo onde eu faço a substituição de arquivo executável qualquer, tipo calc.exe mas que se estiver sendo usado, o original é renomeado para calc.exeold1 e assim é feito a cópia.
Mas peraí. E se o arquivo calc.exe e o calc.exeold1 estiverem sendo utilizados? Aí que entra a recursividade. Não devemos limitar nossa rotina e deixar o programa mais flexível possível.
Abaixo, vou iniciar o código separando por blocos e explicando detalhadamente cada comando.
:: setando as variáveis iniciais set drive_origem=C: set dir_origem=\temp\origem set drive_destino=C: set dir_destino=\temp\destino goto :principal
Logo na primeira linha, você pode perceber que se trata de um comentário.
Você pode utilizar a sintaxe REM mas a vantagem de utilizar “::” é que o batch lê somente os dois primeiros caracteres, enquanto o REM lê a linha toda.
Nas próximas linhas, utilizo o comando set para atribuir as minhas variáveis globais. Isso torna o código mais fácil para manutenção. Você pode ver que as variáveis são a pasta de origem e a de destino do arquivo que iremos copiar.
Na última linha, envio o cursor para o bloco “principal”.
Vou adicionar 3 blocos que funcionam como funções. São executados e retornam o cursor de onde foram chamados. Você irá entender melhor depois que ver como são chamados.
::seta_pasta_origem %drive_origem% cd%dir_origem% goto :eof ::seta_pasta_destino %drive_destino% cd%dir_destino% goto :eof ::apaga_arquivos_destino del %1.exeold* goto :eof
O primeiro bloco “seta_pasta_origem”, acessa o drive e o diretório das variáveis que setamos logo no ínicio, a pasta de origem.
O segundo bloco é igual ao primeiro, mas acessa o drive e o diretório da pasta de destino.
No terceiro bloco, pode parecer um pouco confuso, mas esse %1 é um parâmetro passado por fora do arquivo batch. Por exemplo, quando você chama o programa por meio externo, você deve utilizar “copia_arquivo calc”.
A instrução del vai apagar todos os arquivos que iniciam com “calc.exeold”. O caracter * significa que ele vai desconsiderar os caracteres restantes. Por exemplo, todos os arquivos calc.exeold1, calc.exeold2, e assim por diante serão apagados.
Note que todos os blocos tem o comando “goto :eof” no final. Esse comando retorna o cursor de onde ele foi chamado. Sem ele, o bloco fica perdido e continua executando as próximas linhas.
:principal call :seta_pasta_destino call :apaga_arquivos_destino set seq = 0 if exist %1.exe goto renomeia_arquivos goto copia_arquivo
Aqui inicia o nosso bloco principal. Ele que será responsável por chamar todas as funções do nosso batch.
Logo nas duas primeiras linhas é utilizado a função “call”. Ela move o cursor para o bloco criado e depois retorna de onde parou graças ao comando “goto :eof” no final de cada bloco chamado.
Na próxima linha, eu atribuo o valor 0 para a variável “seq”. Essa variável será responsável para a verificação recursiva do arquivo que iremos copiar. Você entenderá melhor no código recursivo “renomeia_arquivos”.
Continuando, temos um if que verifica se o arquivo já existe. Se ele existir, ele pula para o bloco “renomeia_arquivos”, senão ele pula para o bloco “copia_arquivo”. O bloco principal acabou. Agora depende de qual caminho ele vai seguir. Veremos agora.
:copia_arquivo call :seta_pasta_origem copy %1.exe %drive_destino%%dir_destino% goto fim
Coloquei este bloco agora pois ele é mais simples de entender.
Se o arquivo informado não existir, ele simplesmente chama o bloco “seta_pasta_origem” e realiza a cópia do arquivo da pasta origem para a pasta destino.
No final ele move o cursor para o bloco “fim” para que ele não execute nenhum código que possa estar no meio.
:renomeia_arquivos :: Adiciona um na sequência para renomear arquivos set /A seq = %seq% + 1 :: Verifica se arquivo já está sendo usado e chama recursivamente a função if exist %1.exeold%seq% goto renomeia_arquivos :: Renomeia arquivos que serão copiados (caso existam) if exist %1.exe ren %1.exe %1.exeold%seq% goto copia_arquivo
Bom, agora vamos no bloco mais complexo. Na primeira linha, é feito o incremento da variável “seq”. A sintaxe /A significa que a variável “seq” é um número e que o valor adicionado é para ser somado a mesma e não concatenada.
Na próxima linha, é feito um “if” verificando se o arquivo com a extensão .exeold seguido de um número (Ex: .exeold1) já existe. Se ele existir, é feito um goto para o próprio bloco “renomeia_arquivos”. Daí vem a recursividade. Se o arquivo não existir, ele simplesmente renomeia o arquivo e faz a cópia.
Vou exemplificar o que o batch faz agora.
Supondo que o arquivo calc.exe já exista na pasta de destino.
Então o arquivo calc.exe é renomeado para calc.exeold1 e depois é feita a cópia da mesma.
Mas e se o arquivo calc.exeold1 estiver sendo executado também? No começo da rotina, ele deveria ter sido apagado, mas como está sendo executado ele não é apagado. Então existem os arquivos calc.exe e calc.exeold1 na pasta de destino.
A rotina verifica que o arquivo calc.exe e o calc.exeold1 já existem. A variável de incremento “seq” é incrementada para 2 e a verificação é feita com o nome de arquivo calc.exeold2, que por sua vez não existe. Por fim , o programa renomeia o arquivo calc.exe para calc.exeold2 e é feita a cópia o arquivo calc.exe.
Vamos para o último bloco.
:fim pause
Nossa, esse é o mais difícil de todos!
No fim, utilizei somente o bloco pause para parar o batch exibindo os comandos executados no processo todo.
Você pode utilizar o comando echo para imprimir texto no meio do batch para facilitar o entedimento. Pode também utilizar o comando “@echo off” no início do batch para esconder os comando realizados no batch e no final o comando “@echo on” para mostrar novamente os comandos.
No código que eu vou postar como exemplo, deixei comentado os comandos “@echo off”, “@echo on” e “cls”. Você pode descomentar para ver o resultado criado.
Para testar, faça o seguinte. Copie o arquivo “copia_arquivo.bat” para a pasta C:\Windows\System32.
Crie as pasta C:\temp\origem e C:\temp\destino.
Copie um programa qualquer, como calc.exe na pasta c:\temp\origem
No Executar do Menu Iniciar, digite “copia_arquivo calc”, tecle ENTER e veja o resultado.
Fim, ufa
Para baixar o arquivo batch para testar, segue o link -> Copia Arquivos Batch (6)
-->











A juventude estava esquecendo do poder dos aplicativos em linha de comando, mas graças ao crescimento do Linux e a integração ao terminal, parte dessa cultura renasceu. Eu ainda utilizo muito o prompt de comando e arquivos em lote no Windows, a diferença em relação aos que criava na época do DOS 6.22 é que as vezes uso a extensão .CMD. Embora exista o WSH (Windows Script Host), muito mais poderoso e graficamente atraente, a simplicidade do modo texto justificam eu não abandoná-lo até hoje. Adorei o site, tenho aprendido bastante. Parabéns!
Edson, boa noite!
Agradecemos a visita e muito mais por poder compartilhar suas experiencias e utilizar tecnologias que poucos hoje utilizam.
Abraços!
Olá Edson, boa noite!
Obrigado pelo comentário.
O WSH eu não conhecia. Foi interessante você ter comentado pois vou dar uma pesquisada e quem sabe em um futuro eu não poste sobre ele?
Bom dia Mauricio.
Estava implementado um bat aqui na empresa em que eu trabalho para executar um outro aplicativo em linha de comando com alguns parametros opcionais e seu texto me ajudou bastante principalmente na parte que explica o bendito :eof que faz o script retornar da onde foi chamado que era exatamente isso que eu nao estava conseguindo rs!
Vlw!
Abracos!