Writing to file with batch - windows

I'm trying to get a batch file to take user input and place it in a file... here is my code so far.
set /p input path=Path:
echo %path% >> log.txt
when I turn echo off, it's putting a "1" infront of the chevrons like so:
echo C:/Example/Path 1>> log.txt
the system can not find the file specified.
Please can anyone explain this

Certainly - I'll answer the question asked.
Originally, >somewhere or any redirection sent the data to the destination specified.
With the changes to the NT version, this was expanded. A digit DIRECTLY preceding a redirector means logical file number where 0=STDIN (standard-input) 1=STDOUT (standard output) and 2=STDERR (Standard error.) The others are undefined. This can cause problems where the data (typically) to be output ends with a digit, hence the >filename echo ... syntax
Consequently, for backward compatibility, (eg) >nul is still processed as it always has been, but it's ECHOed in its explict form 1>nul - sending STDOUT to nul to distinguish it from 2>somewhere_else

try this:
set /p "MyNewPath=Path: "
>>log.txt echo %MyNewPath%

Your SET statement is wrong. :-) Also, PATH is already assigned in the environment (the Windows PATH, and altering it may cause problems with running other commands in your batch file.
Try this instead:
set /p "Input=Path: "
echo %Input% >> log.txt

Related

Stream 3 handle redirection causes output flood

I was playing with wmic when this command
wmic<nul 3>nul
produced this:
The strange thing is, any command will work, but only stream 3 causes the output flood.
I googled and searched on SO "cmd output flood" and cannot find any duplicates nor any results.
Question: Why only stream 3 works?
Update: Likewise,
>con 3<con :
completely disables STDOUT!
I think that, as pointed by aschipfl, my answer to their question explains what the source of the problem is.
Please refer to them for the inner details, this answer is just a summary to explain the different behaviour.
When a redirection is created the code inside cmd handling this task tries to avoid problems saving the original handles to the streams that are being redirected so the redirection process can be reverted.
But the way the used function (standard _dup()) works and the order used when creating the redirection can alter the internal structures used in such a way that at the end the code reversing the redirection uses wrong information.
In short:
<nul 3<nul wmic
<nul saves the stdin handle in &3 and assigns nul stream to &0
3<nul saves the handle inside &3 into &4 and assigns nul stream to &3
wmic is executed. As it is reading from nul (assigned to &0) it can not read anything and ends.
&0 is restored from &3 where it was saved, BUT now &3 points to nul
&3 is restored from &4. Now it points to the original stdin
In the original aschipfl's question the observed behaviour was command prompt closing. After code execution
< file1 3< file2 echo/
the redirection cancel process leaves stdin stream pointing to a disk file (file2). cmd starts to read this file for commands to execute (as it normally does from stdin) and at end of file the read operation fails and the cmd instance ends. If you want a convoluted way of seeing it in work to start notepad you can try
( >file1 echo notepad ) & ( <nul 3<file1 break )
But in this question the behaviour is different because the stream assigned to &3, that will be copied to stdin once the redirection is reverted, is not a disk file but nul
<nul 3<nul echo/
Once the command is executed and redirections are reverted stdin stream is associated with nul device
cmd shows the prompt and tries to retrieve a new command reading from nul
The read operation ends but does not retrieve anything so cmd does not execute anything
goto 2
The question "Why only stream 3 works?" (in the sense of it does not work ;) ) is not correct. You can do something like
1>file1 <nul 4<nul echo/
and get the same result using different streams. Or you can do
3<nul <nul echo/
and it will work (in the sense of it works).
The order in which you request the redirection of the streams, how they are handled by cmd internal code and the existence of still active previous redirections can decide the success or failure of the command.

Odd behaviour from FOR command with seemingly harmless space in it. Explanation?

I ran into an "odd" (to me) problem while writing a batch file, and hope someone can explain why it does what it does... I had a batch file that built-up a moderately complex command-line, and I wanted it to echo what it had built to the screen before executing so that I could check that it had been built correctly. There are other ways I could have done this1, but for various reasons I tried something of the form:
for %%a in (echo "") do %%~a complicated-command-line-with-parameters
The thought being that it would run the do part twice: once with %%a set to echo (displaying the command to the console) and once with it set to "": the expectation was that it would actually execute the command (using %%~a would strip the double-quotes and all that would be left is the command itself). However, while the echo worked, the command itself was not executed.
For a minimal replication, run the following from a command-prompt:
C:\>for %a in (echo "") do %~a dir
C:\>echo dir
dir
C:\> dir
As can be seen, it runs the echo command fine, but it seems that the space in front of dir prevents it from being executed.
Note, though, that manually running a command with a leading space is fine:
C:\> dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
and, were it somehow trying to run the command <space>dir, then it (probably) would have complained of a missing command:
C:\>" dir"
'" dir"' is not recognized as an internal or external command,
operable program or batch file.
Question: The space between %~a (which is an empty string) and the command to be run seems to be causing the whole line to be ignored... does anyone know why?
Note: It make no difference whether it is run from the command-prompt (as above) or from within a .BAT file (after changing %a to %%a etc.). Nor does it make any difference whether the command-to-be-run is a built-in command (e.g. dir as above) or a standalone program.
Further evidence that it is the space between %~a and the command that is causing the problem comes from the "fix" that I found:
C:\>for %a in ("echo " "") do %~adir
C:\>echo dir
dir
C:\>dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
By adding the "separating space" to the "echo " string inside the for command, and removing it from the do clause (...do %~adir), the command works as I originally expected (although I dislike not having a space in front of the command).
After skimming the (somewhat daunting) top answer to the question How does the Windows Command Interpreter (CMD.EXE) parse scripts? that SomethingDark helpfully linked to, a cleaner alternative that seems to work is:
C:\>for %a in (echo call) do %~a dir
C:\>echo dir
dir
C:\>call dir
Volume in drive C is OS
Volume Serial Number is A8BD-F861
...
There are probably idiomatic situations where having the extra call might affect something, but for the moment, it seems to work as desired.
1 I could have put #echo on just before the line inside the batch file, but that also causes the prompt (e.g. C:\MyDirectory\SubDir>) to be shown, which I didn't want. The other "standard fallback" is to just duplicate the line and stick echo in front of the first copy, but then it's too easy for them to get out-of-sync!
SomethingDark already pointed to the explanation.
It's the command vs argument token splitting of a line.
In your case the command token is always %~a this will be replaced later, but even when its empty, the parser will not reevaluate the command token.
With your fix, the dir command is always part of the command token.
But when echo is prefixed it can still echo the remaining part.

pipe operator in batch script

Sorry if this is a duplicate question :-)
I got below line of code from a batch script. (script.bat)
echo %DATE% %TIME% some text ... >> %logfile% | c:\path\script1.bat >> %logfile%
What is the significance of pipe (|) symbol here?
The script.bat is working fine from command line (script.bat), and it is running script1.bat as well.
While running script.bat from scheduled task it intermittently failed to run script1.bat, exiting with errorlevel 1.
Anyone have any idea what this | doing here :-)
I'm assuming you know what pipes are normally used for. In your code, both sides of the pipe have their stdout redirected to a file. So the pipe is not fulfilling its normal purpose.
The way Windows implements pipes is to launch a new cmd thread for each side of the pipe.
In your case, the | is a quick and dirty way to instantiate parallel processing of the two commands.
Update
I just realized that both sides of the pipe are redirecting stdout to the same log file. That should never work, because only one cmd process (or thread) at a time can have the file open for write access. It certainly does not work for me from the command line. I get the following error: The process cannot access the file because it is being used by another process. The only way that does not fail is if logfile is set to nul.
If I had to guess, I think the original developer intended to use & instead of |. There is no reason to run a single ECHO statement in parallel with another batch script. It looks like the first statement is simply a timestamp.
I think your code should look like
echo %DATE% %TIME% some text ... >> %logfile% & call c:\path\script1.bat >> %logfile%
or better yet
>>%logfile% (
echo %DATE% %TIME% some text ...
call c:\path\script1.bat
)

What does a forward slash before a pipe in cmd do to remove the line ending of an echo?

This code:
#echo off
echo/|set /p ="Executing backup...."
echo/|set /p =" backup procedure"
... came from Echoing in the same line and produces the below output in a cmd window:
Executing backup....backup procedure
However, I cant seem to find an explanation through google on what the forward slash does to the ¿pipe? to cause set's output to be echoed to the console / stdout
If anyone could also suggest a good website for learning more about cmd / cmd programs' features like this, it would be appreciated.
The echo/ is simply a way of printing only an empty line, instead of ECHO IS ON for a single echo.
But in this case it's completly unimportant, as the only use of the echo is for creating some stuff for the pipe, so the set /p will not wait for user input.
But this way to echo text without a linefeed is very inefficient, as a pipe creates two new instances of cmd.exe.
It's much simpler and faster to use
<nul set /p "=My Text"
The redirect from NUL will also stop the waiting for user input.
Care of https://stackoverflow.com/users/1201210/tenterhook
1) echo prints the result of set /p =... with or without the / before the pipe, so I'm not sure what your question is asking
2) (It will also print set /p =... with random junk after the echo, too, since it's reading the piped stuff and not the arguments it receives.)
I will hence suggest edits to the referenced SO post, to prevent others confusion.

Is there any way to trace through the execution of a batch file?

I inherited some large batch files, and I'd like to rewrite them to a more "developer friendly" language.
I'd like to find out the following things:
what other scripts it calls
what other processes it starts
what files does it write to
what environment variables it uses, which ones does it set
For the last point, I'm aware I can do this before I start:
set > original_environment.txt
And after I run it, I can do this:
set > new_environment.txt
and just do a diff between them ... but I'll probably miss some variables that may be unset when the script finishes ( or even all of them if the script's ran under setlocal ).
Is there any way of finding all those things without me adding tons of echo statements throughout the script code?
Is there such a tool that can monitor the process started by the batch file and tell me everything it did?
You can just look inside them and figure out what they do.
You can also remove any echo off statements and # preceding commands; that way every command is output before it's run and you can redirect the output to a file to study it later.
There is no debugging tool for batch files that I am aware of—but I contemplated writing one once.
There is no direct way to do it. But it's not impossible to create one.
Since Windows XP/Vista/7 came out the good'ole set of DOS batch commands has been greatly upgraded, although not many uses them or even RTFM (FOR /??)
So here I give you, a simple pure-batch TRACER that utilizes the FOR /F line-parsing switch:
#ECHO OFF
FOR /F "delims=" %%L IN (%1) DO (
CLS
ECHO __________________________________________________
ECHO ENV. VARIABLES *BEFORE*
SET
ECHO __________________________________________________
ECHO LINE
ECHO %%L
ECHO __________________________________________________
ECHO Hit any key to execute the line ...
PAUSE > NUL
ECHO __________________________________________________
ECHO EXECUTE
%%L
ECHO __________________________________________________
ECHO Hit any key to fetch the next line...
PAUSE > NUL
)
ECHO END OF FILE
You can take it as a start and modify it as you go.
Here's how you'd use it:
DEBUG.BAT TEST.BAT
And I'll also give you a test file to try it out:
#ECHO OFF
ECHO Hello World!
SET aaa=1
SET bbb=2
ECHO Doing step 2
SET aaa=
SET ccc=3
ECHO Doing step 3
SET bbb=
SET ccc=
ECHO Finished!
This DEBUG.BAT thing, however, due of its simplicity, has some limitations BUT which can be worked around if you slap enough BATCH-fu in there.
It cannot process multi-line blocks :: This can be worked around by having the FOR commands parse tokens and build the lines as they come in, and IF it encountered an open parenthesis, just dump the parenthesis block content to a temporary file and then call itself on the tempfile e.g. DEBUG tempfile.bat
It cannot process jumps :: You can of course, do an IF check for a GOTO label then do a FOR /F to parse out label itself, then maybe utilize the second argument %2of DEBUG.BAT to specify the label to jump to, in which case if this very argument is specified you'd just spin the FOR /F until the desired label came into view and then proceeds with normal debugging on the next line.
There is too much information from a single SET :: Just do what you did with the SET > before.txt and after thing but do it on each line and then run a cmd-line DIFF tools on the files (plenty are available on the net). Then you'll get a DIFF of each variable that has changed since last step. You might even be able to avoid the env. variables mess altogether by slapping in SETLOCAL and ENDLOCAL in there and then you'd get just the local SETs ... but YMMV.
Those are some. If you've found some show-stopping limitation or whatever enhancements would help you nail that last bug, feel free to just let me know (via the comments) and I'll try to help you if I can.
Hope this helps.
No, there is no way to debug old style batch files. You can, however, just get rid of all the ECHO OFF statements, and then all the commands and output will be echo'd to the console when you run them.
If you are willing to spend some money you should take a look at the Running Steps batch file IDE and its debugging capabilities.
I didn't test it, but it has some features that might help you in your task:
...
Visual Studio-like debugging environment.
Rich set of debugging commands (step into, step over, step out, and more)
Rich Project analyzer to find your errors and warnings in no time.
Integrated support for delayed-expanded environment
variables.
Multi-type breakpoint definitions to fit your multiple debugging needs.
Complex pipeline and redirection support with multi-color highlighting.
Environment variable visualization and modification support.
Expanded information window for true variable definition visualization.
Impressive 'For command' unrolling feature.
Interactive callstack and Parameters window.
...
They also offer a trial version.

Resources