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)

Sobre Mauricio Naozuka

Mauricio Naozuka já escreveu 2 artigos no portal.

Analista de sistemas e programador Delphi. Viciado em lógica de programação independente da linguagem. Atualmente, engatinhando a carreira como desenvolvedor .NET. Fã assíduo de jogos de RPG e geral. Encontrei a mulher da minha vida, tenho uma coleção de mangás e um gato-aranha chamado Hermann. :)

-->

4 Interações

  1. Edson Bakana disse:

    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!

  2. Mauricio Naozuka disse:

    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?

  3. Antonio disse:

    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!

Interaja

Qual a soma entre:
2 + 1