简体   繁体   中英

batch file acts differently when launched from within another batch

So... hey guys and gals. I have the weirdest problem. I wrote this batch file which generate a text file

My code which for some reason gets really messed up is bellow, you can see a better version here

@ECHO OFF

IF NOT EXIST file.txt goto generate
ECHO Erase the file>%0\..\file.txt

:generate
ECHO.
ECHO.
ECHO generating Table file for you
ECHO Please enter a name: 
SET /P name=

ECHO.

ECHO Please enter the date: 
SET /P date=

ECHO.

ECHO Please enter the time: 
SET /P time=

ECHO. 
ECHO.
ECHO Huzzah!

ECHO |set /p =%name%        %date%       %time%>%0\..\file.txt

:repeat
ECHO Do you want to add another entry? (Y/N) 
SET /P answer=
IF /i {%ANSWER%}=={y} (GOTO yes) 
IF /i {%ANSWER%}=={yes} (GOTO yes)
GOTO no

:no EXIT /B

:yes
ECHO.
ECHO.

ECHO Please enter a name: 
SET /P name=

ECHO.

ECHO Please enter the date: 
SET /P date=

ECHO.

ECHO Please enter the time:
SET /P time=

ECHO.
ECHO.
ECHO Huzzah!

ECHO.>>file.txt 
ECHO |set /p =%name%        %date%        %time%>>%0\..\file.txt
GOTO repeat

And it works! Here is the glitch, I don't want to just run this file, I want to run this from within another file.

Sooooo in my other .bat I have this line

@call %0\..\generate_file.bat

Again it works great, calls it up, runs it, and if I only have one entry then everything is fine... however if I enter yes and go to enter another entry it doesn't create a new line it just keeps appending the new entries onto the old ones. If I just launch generate_file.bat by itself though, it works as intended.

Any one have any ideas?

Eek! Please hand me my LARGE bottle of aspirin!

Ansgar seems to have edited the original to match the pastebin version - and if that's correct, there appears to be no way in which this routine could work - call or no...

This line

:no EXIT /B

won't work. Any data on a label-line is ignored, so there's no way of EXIT ing the procedure. This MUST be written as

:no
EXIT /B

Next little quibble is the previous line. Unlike languages like PASCAL or DELPHI. batch simply executes line after line until it reaches a CALL , GOTO EXIT or END-OF-FILE. It has no concept whatever of "blocks" in the sense of functions or procedures. Labels are just markers.

Hence, the

GOTO no

is superfluous. The label no will be reached UNLESS ANSWER is y or yes - and the parentheses around the GOTO yes are also redundant.

The next little problem is that pressing just ENTER in response to a SET/P will not change the variable's value - it will retain any value it had before the set/p .

The consequence will be that should answer be set to y , then responding enter will leave answer set to y - it won't clear answer .

The way to overcome this is to specifically set the value before executing the set/p

SET "ANSWER="
SET /P ANSWER=

But, as often happens, this is a two-way street. If you code

SET "ANSWER=Y"
SET /P ANSWER="[%ANSWER%] "

Then the SET/P will prompt with [Y] - note that the quotes are only required here to enclose the space. Don't want the space? Omit the quotes...

Now this is probably more important for the entry of name and - oh-oh - another trap. date and time are logical names for the variables you want. Problem is, they're too logical. They're magic variables - and it's best not to mess with them.

Any magic variable may be set in a batch program just the same as an ordinary variable BUT if they are left un-set, the system sets them to - well, magic values. By magic, of course. %date% contains the date, %time% the time - and there are a bunch of others - see SET /? from the prompt for a list.

The problem with the magic variables is that they don't appear in the list of system-initialised variables you'd get from executing SET (without parameters!) It's not a good idea to change these, either. Batch programs will usually assume their values.

Now one of the system-initialised variables is path - the list of directories that get searched to find an execuable if no explicit path is made and it's not in the current directory.

This last point is significant when it comes to the %0\\..\\ consruct. " %0 " on its own is the batch filename. It may be fred or fred.bat or C:\\somewhere\\somewhereelse\\fred.bat - many different things depending on circumstances. %0\\..\\file.txt may therefore be different things - file.txt in the current directory being the most likely.

So - your original batch checks to see whether file.txt exists in the current directory, then comments Erase the file into %0\\..\\file.txt if it does already exist - probably into .\\file.txt (ie file.txt in the current directory) - so it overwrites the existing file.

Regardless, the routine then asks for the three data items and uses this peculiar construct

ECHO |set /p =%name%        %date%       %time%>%0\..\file.txt

Which simply responds nothing into no variable, but prompting with the data line which gets directed to the file - creating a new file or overwriting (again) an existing one (a single > means "in a new file")

Then you prompt for another entry, this time APPENDING ( >> ) to the file.

It would be far simpler if you deleted any existing file, then appended all of your datalines to a new file - a >> will create a file if it doesn't already exist.

So - here's a partial revision. I've not removed superfluous parentheses and GOTO s, nor have I cleared or preset data values prior to SET /P s or incorporated prompts into them. I've even left the variable names.

Note how I've set filename - gets set once, so that the variable %filename% can be used for the file rather than constantly repeating the same string - painful if you decide to change the filename...

@ECHO OFF
SET filename=%~dp0%file.txt
ECHO %filename%

IF NOT EXIST %filename% goto generate
ECHO Erase the file %filename%
DEL %filename%

:generate
ECHO.
ECHO.
ECHO generating Table file for you

:yes
ECHO Please enter a name: 
SET /P name=

ECHO.

ECHO Please enter the date: 
SET /P date=

ECHO.

ECHO Please enter the time: 
SET /P time=

ECHO. 
ECHO.
ECHO Huzzah!

ECHO(%name%        %date%       %time%>>%filename%

:repeat
ECHO Do you want to add another entry? (Y/N)
SET /P answer=
IF /i {%ANSWER%}=={y} (GOTO yes) 
IF /i {%ANSWER%}=={yes} (GOTO yes)
GOTO no

:no 
EXIT /B

Hope you find this useful! I'm off for a lie-down.

Replace this:

ECHO |set /p =%name%        %date%        %time%>>%0\..\file.txt

with this:

>>"%~dp0\file.txt" echo %name%        %date%        %time%

%0 is the script file itself. Use %~dp0\\file.txt instead of %0\\..\\file.txt to access a file in the same folder. Put the path between double quotes to avoid surprises due to unexpected spaces. And put the redirection before the command to avoid weird output redirection issues like the one you observed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM