Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

batch file echo on/off not working properly

Tags:

batch-file

I'm not really used to making batch files, so I'm probably doing something wrong, but I'm really having trouble with echo off/on. (That said, if you see any other error that I missed, feel free to point it out)

Here's a simplified version of my code:

@echo off
setlocal
set args=
set dir="."

:getargs
IF "%2"=="" (
    set dir="%1"
    goto callbatch
)
set args=%args% %1
shift
goto getargs

:callbatch
for %%f in (%dir%\*.txt) do (
    echo processing %%f
    "%BATCHHOME%\batch.bat %args% %%f
    echo
)

So basically, I have a batch file in BATCHHOME that does something to a single txt file and I want to produce a batch file that will process all the txt files in a given directory. The lone echo in the loop is to better illustrate the problem.

Now, here's where I have a problem. The output of this looks like:

processing foo\text1.txt
some output from batch.bat
ECHO is on.

C:\somedir>(
echo processing foo\text2.txt
   "C:\the\path\of\batch.bat" the arguments here foo\text2.txt
)
ECHO is on.

C:\somedir>(
echo processing foo\text3.txt
   "C:\the\path\of\batch.bat" the arguments here foo\text3.txt
)
ECHO is on.

(etc)

Ok... I don't know why the batch file I'm calling turns echo on, but I didn't make it, so I'll just turn it back off each time! I changed the last part to:

:callbatch
for %%f in (%dir%\*.txt) do (
    echo processing %%f
    "%BATCHHOME%\batch.bat %args% %%f
    echo off
)
echo
echo on
echo
echo Finished!

(Again, the two lone "echo" are there for debug) So now the output looks like this:

processing foo\text1.txt
some output from batch.bat
processing foo\text2.txt
some output from batch.bat
processing foo\text3.txt
some output from batch.bat
(etc.)
ECHO is off.
ECHO is on.
Finished!

This would be almost perfect, but there's something a bit odd. If echo is on, then why does it display "Finished!" instead of "echo Finished!"? The bigger (but related) problem however is that when the batch file is done, I don't get my path displayed any more. In other words, instead of having:

C:\Somedir>_

I just get

_

I need to type "echo on" manually to get the path to show again. Where did I go wrong?

edit: Just to clarify, I am aware that "echo" by itself prints the current status of echo. That is what I intended. In the first code, they are there to show that echo mysteriously turns on after I call the other batch file. In the second one, it is there to show that echo is on at the end of the batch file, yet the behaviour is as if it wasn't. THAT is my problem.

like image 325
PhilBel Avatar asked Aug 22 '12 16:08

PhilBel


Video Answer


1 Answers

I see your problem now - and it is an interesting one. You are calling a batch file from within a batch file without using CALL.

If batch A executes batch B without CALL, then the entire batch processing is terminated once batch B finishes - Batch A will not resume where it left off. Once batch processing is terminated the ECHO state is returned to the original state that existed before batch processing began, normally ON.

But your scenario is a bit more complicated because your "call" to the 2nd batch is within a FOR loop. So the FOR loop continues to execute the DO commands that are cached in memory, even though batch processing has terminated. The commands are now executing in a command line context with ECHO ON.

In your 2nd scenario you explicitly turn ECHO OFF within the FOR DO block. After the 1st "call" you are again in command line context, and then you turn ECHO OFF. Hence your need to turn ECHO ON manually.

I'm not sure how the lines after the FOR loop are getting executed. You said you have simplified the code, so I am assuming the code you are actually running has those additional lines in some kind of code block as well. The lines would then be buffered and would still execute even after batch processing terminates. This would also explain why the line that prints "Finished!" is not echoed even though ECHO is ON. All commands within a block of code use the ECHO state that existed prior to entering the outer most block of code. The one exception is a FOR DO block uses the ECHO state that existed prior to entering the DO block.

Both sets of code you posted do not run because each has an unbalanced quote in the line that "calls" the 2nd batch file.

The fix is to simply add CALL to the statement that executes the 2nd batch file. Then batch processing will continue, the ECHO state will remain OFF, and the parent batch will resume where it left off properly.

I also improved the argument parsing logic and the use of quotes. You should strip quotes from each argument using ~ before explitly adding your own. The argument may already have its own quotes. And any time a file name or path is passed as an argument, it should be quoted in case it contains space or special characters. You need to keep track of whether the value in a variable is quoted or not. I generally find it easier to keep my variable values unquoted and then explicitly add quotes when I need them.

@echo off
setlocal
set args=
set "dir=."

:getargs
IF "%~2"=="" (
    if "%~1" neq "" set "dir=%~1"
    goto callbatch
)
set args=%args% %1
shift
goto getargs

:callbatch
for %%f in ("%dir%\*.txt") do (
    echo processing %%f
    call "%BATCHHOME%\batch.bat" %args% "%%f"
    echo
)
like image 152
dbenham Avatar answered Nov 20 '22 03:11

dbenham