I have a scripting system driven by powershell which calls BAT files
I want to record the Envs at the end of the BAT session so that they are available for the next BAT file. I have found what I did, did not capture changes from the BAT file...
More
I had code like
& cmd.exe "/c $script $optionalArgs & (echo Name^=Value&SET) > ""c:\path\end_envs.csv"""
$script == dosomework.bat
which appeared to work, i.e. the csv file is created with env's BUT does not have the ones created by $script... Rather seem to be the ENVs of the initial cmd.exe call...
After adding the 'echo xx' lines to a BAT file and calling this at the bottom of the bat file referenced in $script, all is OK, I see the env at the end of the $script BAT file
Is there a way to fool a cmd.exe /c to consider my extra echo info as part of the called script ?
Thanks
OR...
sae this as $$script.bat
#ECHO OFF
(
echo Name=Value
CALL $script %*
SET
)>"c:\path\end_envs.csv"
and modify your code to like
& cmd.exe "/c $$script $optionalArgs"
whee $$script.bat may naturally be any name you like.
Note that this assumes that $script.bat (the one you are actually executing) does not contain a setlocal instruction.
If $script is variable, then in the batchfile $$script.bat try
#ECHO OFF
SETLOCAL
(
echo Name=Value
set "params=%* "
CALL %1 %%params:* =%%
set "params="
SET
)>"u:\envs.csv"
GOTO :EOF
This assumes there are no confounding factors (parameters containing characters to which cmd is sensitive, for instance - normal alphameric strings should be fine)
So
write out the header line
set params to the supplied parameter list + a space
execute a subroutine firstparameter with parameter(s) remainingparameters. The call ...%%params:* =%% syntax means "the value of params, up to and including the first space"
clear params
list the remining environment variables.
The destination filename is of course up to you. I used a name that's convenient for my system.
So - you would call this script with a parameter of (the first name of the script you want to run) + (any other parameters you require)
Simplest would probably be to add
(echo Name^=Value
SET) > "c:\path\end_envs.csv"
to the end of $script (or at least, force those two lines to be executed just prior to exit)
Related
I have the following batch file to make git diff invoke spreadsheet compare UI in windows. So I'm trying to pass the git diff's 2nd (old file) and 5th (new file) arguments to spreadsheet compare in order to make it compare the file using git diff.
So now, this batch file only successfully handles files with NO spaces in the file names, it CANNOT handle files with spaces in the file names.
What code should I add to this script to make this batch code handles file with spaces:
#ECHO OFF
set path2=%5
set path2=%path2:/=\%
ECHO %2 > tmp.txt
dir %path2% /B /S >> tmp.txt
C:/"Program Files"/"Microsoft Office"/root/vfs/ProgramFilesX86/"Microsoft Office"/Office16/DCF/SPREADSHEETCOMPARE.EXE tmp.txt
It currently throw errors like this:
Unhandled Exception: System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional)
at System.IO.Path.GetFileName(String path)
at ProdianceExcelCompare.Form1.StatusReady()
at ProdianceExcelCompare.Form1.Init()
at ProdianceExcelCompare.Form1..ctor(String instructionFile)
at ProdianceExcelCompare.Program.Main(String[] args)
fatal: external diff died, stopping at London comparison.xlsx
See the following answers on Stack Overflow:
How to set environment variables with spaces?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
They explain the recommended syntax set "VariableName=variable value" to define an environment variable and the reasons recommending this syntax.
Why does ECHO command print some extra trailing space into the file?
It explains why the space character left to redirection operator > on an ECHO command line is also written into the file as trailing space and how to avoid this safely on variable text written into the file.
See also Microsoft documentation about Using command redirection operators.
On other command lines than ECHO a space left to > is usually no problem.
It is in general wrong to use multiple times " within an argument string like a file or folder path. There should be just one " at beginning and one " at end. This is explained by help of Windows command processor output on last help page on running in a command prompt window cmd /?.
The Microsoft documentation about Naming Files, Paths, and Namespaces explains that the directory separator on Windows is \ and not / and therefore / should not be used in batch files on Windows in file/folder paths.
The help output on running in a command prompt window call /? explains how the arguments of a batch file can be referenced with which modifiers.
The code rewritten according to information posted above and on the referenced pages:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
>"tmp.txt" echo %2
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
The first line in tmp.txt contains the second argument as passed to the batch file, i.e. without or with surrounding double quotes.
The following code is necessary to write the second argument safely always without " into file tmp.txt even on second argument passed to the batch file is "Hello & welcome!":
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "path2=%~5"
set "path2=%path2:/=\%"
set "Argument2=%~2"
setlocal EnableDelayedExpansion
echo !Argument2!>"tmp.txt"
endlocal
dir "%path2%" /B /S >>"tmp.txt" 2>nul
"%ProgramFiles%\Microsoft Office\root\vfs\ProgramFilesX86\Microsoft Office\Office16\DCF\SPREADSHEETCOMPARE.EXE" "tmp.txt"
endlocal
>tmp.txt echo %~2 cannot be used as not working for something like "Hello & welcome!". Windows command processor would interpret the first string separated by normal space, horizontal tab, comma, equal sign, or no-break space (in OEM code pages) delimited string after & as command or application to execute as described by single line with multiple commands using Windows batch file.
"tmp.txt" could be written everywhere in both batch files also with just tmp.txt. But it is never wrong to enclose the complete file/folder argument string in double quotes even on not being really necessary because of the string does not contain a space or one of these characters &()[]{}^=;!'+,`~. So it is good practice to always enclose a complete file/folder argument string in double quotes. For example running a replace on both batch files searching for tmp.txt and using as replace string %TEMP%\%~n0.tmp would result in using instead of tmp.txt in current directory a temporary file with name of batch file as file name and file extension .tmp in directory for temporary files independent on what is the name of the batch file and what is the path of the directory for temporary files.
The last suggestion is reading this answer for details about the commands SETLOCAL and ENDLOCAL.
The temporary file should be also deleted finally before reaching an exit point for batch file execution.
You can use quotes as below:
It treats the string in quotes as a title of the new command window. So, you may do the following:
start "" "yourpath"
Found it in the below link :
https://ccm.net/forum/affich-16973-open-a-file-with-spaces-from-batch-file
I am writing a batch script for the 6th assignment in my class and I have hit a snag when I am pretty much finished. (We usually focus on bash scripting, so I am new to batch)
The script functions as desired the first time running it; but behaves differently when running it for the second time.
Essentially, the script checks the value of an argument if it exists and runs specific code depending on the value. For example, if the argument is "1", then it checks the PATH variable for a directory and creates it if it doesn't exist, and if it does exist - nothing happens and it just continues the script.
The issue occurs when running the script for a second time after the PATH is modified. I receive the output "\Common was not expected at this time".
I had a similar issue when running the script the first time, but managed to fix it by including Quotation marks on both side of the evaluation on the IF statement, but now I am unsure of where to continue with this.
My code is as follows:
#echo on
IF "%1%" == "0" (
SET "VAR1=%path%"
echo.%VAR1%|findstr /C:"App0" >nul 2>&1
if errorlevel 1 SET "PATH=%PATH%%cd%\App0;"
if not errorlevel 1 echo Found
goto errorBypass
) ELSE IF "%1%" == "1" (
SET "VAR2=%path%"
ECHO %VAR2%
echo.%VAR2%|findstr /C:"App1" >nul 2>&1
if errorlevel 1 SET "PATH=%PATH%%cd%\App1;"
if not errorlevel 1 echo Found
goto errorBypass
) ELSE IF "%1%" == "" (
IF "%HUMBER_HOME%" == "" (
goto Error2
) ELSE (
CALL "HUMBER_HOME\bin\setEnv.bat"
goto errorBypass
)
)
echo HERE
:Error2
echo Error2
:errorBypass
call "run.bat"
Also, so I know for future reference - is there an effective way to debug by going line by line? or a command that can output the particular line where the error occurred? I find it somewhat difficult when one error can be caused by multiple issues in different places.
Referencing a batch file argument
Open a command prompt window and run call /?. The output help explains how to reference batch file arguments. %1 references the first argument as passed to the batch file. That can be for example 1 (not quoted argument string), but also "1" (quoted argument string). %~1 references first argument string with surrounding double quotes removed.
It is wrong to add one more % after the argument reference. The syntax %variable% is used to reference the string value of an environment variable. Batch file arguments are referenced only with percent sign and digit without or with a modifier between. There is no more percent sign after the digit. That is also the reason why 1, 2, 3, ... are not possible as names for environment variables.
So not good is IF "%1%" == "0" ( because of this can result on batch file called with "1" as first argument in execution of the command line:
IF ""1"" == "0" (
The much better syntax is IF "%~1" == "0" ( which results in execution of the command line:
IF "1" == "0" (
See my answer on difference between “…” and x“…” in batch for more details on how to evaluate batch file arguments.
Appending a folder path to local PATH
The environment variable PATH holds a comma-separated list of folder paths whereby the list separator is a semicolon instead of a comma.
Therefore a ; at end of PATH means there is one more folder path which is an empty folder path. It is possible to specify an empty folder path in the middle or at end of PATH, but it is bad practice to do so because of PATH should not contain empty folder paths.
For that reason the following command line in your code is not good:
if errorlevel 1 SET "PATH=%PATH%%cd%\App0;"
There is also missing ; in case of PATH does not already end with a semicolon which could be a reason for the error message on second execution of the batch file.
The better code can be seen below on completely revised batch file code.
Referencing current directory
It is possible to reference the current directory with %CD% which can differ from batch file directory referenced with %~dp0. %~dp0 references drive and path of argument 0 which is the batch file itself. The batch file path string referenced with %~dp0 always ends with a backslash. Therefore no additional backslash should be used after %~dp0 on concatenating it with a file/folder name.
The dynamic environment variable CD ends usually with no backslash at end. So in most cases %CD% must be concatenated with an additional \ with a file/folder name. But there is one exception which must be taken into account on using %CD% in a batch file: %CD% expands to a string with \ at end on current directory being the root directory of a drive, for example C:\ or D:\. So it is always necessary on using %CD% to check if the string already ends with a backslash before appending a file/folder name without or with an additional backslash.
Other recommendations
The usage of a command block starting with ( and ending with ) should be avoided on using environment variables defined/modified within a command block and referenced within the command block as this requires the usage of delayed expansion as explained by help output on running set /? in a command prompt window on an IF and a FOR example on which command blocks are used usually. The Windows command processor is designed primary for executing one command line after the other. The usage of command blocks can speed up the execution of a batch file in some cases, but in many cases it is better to avoid them.
See debugging a batch file with a short description how to debug a batch file. A single step execution is not really possible. But cmd.exe shows on which line or command block an error occurred resulting in exiting batch file execution and what is the error.
Revised batch file code
Here is the revised batch file code:
#echo off
goto Main
:AddPath
echo %PATH%;|%SystemRoot%\System32\findstr.exe /I /C:"\%~1;" >nul 2>&1
if not errorlevel 1 echo Found %~1 in PATH& goto :EOF
set "Separator=;"
if "%PATH:~-1%" == ";" set "Separator="
if "%CD:~-1%" == "\" (set "AppPath=%CD%%~1") else set "AppPath=%CD%\%~1"
set "PATH=%PATH%%Separator%%AppPath%"
set "AppPath="
set "Separator="
goto :EOF
:Main
if "%~1" == "0" call :AddPath App0 & goto errorBypass
if "%~1" == "1" call :AddPath App1 & goto errorBypass
if not "%~1" == "" goto RunApp
if "%HUMBER_HOME%" == "" goto Error2
if exist "%HUMBER_HOME%\bin\setEnv.bat" (
call "%HUMBER_HOME%\bin\setEnv.bat"
goto errorBypass
)
echo File "setEnv.bat" in subdirectory "bin" in directory
echo defined by environment variable HUMBER_HOME not found.
echo HUMBER_HOME directory: "%HUMBER_HOME%"
echo/
pause
goto :EOF
:RunApp
echo HERE
goto :EOF
:Error2
echo Error2
goto :EOF
:errorBypass
if exist "run.bat" call "run.bat"
There is defined the subroutine AddPath at top of the batch file which is a bit unusual. So the second line with goto Main results in jumping over code of the subroutine on starting the execution of the batch file.
The subroutine AddPath is called with either App0 or App1 on first argument being 0 or "0" or 1 or "1".
The first line in AddPath outputs current value of local environment variable PATH with a semicolon appended and redirects this output to FINDSTR which searches case-insensitive and literally for the first argument string passed to the subroutine after a backslash and ending with a semicolon. The additional \ and ; should avoid a false positive on any folder path in PATH containing by chance also App0 or App1 somewhere in the middle of the folder path. This small enhancement is not 100% fail safe, but should be good enough.
FINDSTR exits with 0 on searched string found in line. In this case just an information message is output and the subroutine is exited which results in batch file execution being continued on main code on which the subroutine was called before. Otherwise the passed application name must be added to local PATH.
See also:
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
So first the environment variable Separator is defined with ; as value. But if local PATH already ends with a backslash although it should not, the environment variable is deleted immediately. Please note that the command line comparing last character of PATH with ; can fail if PATH ends with ". So this simple version is not 100% fail safe.
Next the current directory path is concatenated with the passed application folder name without or with an additional backslash depending on current directory being root directory of a drive or a subdirectory of any directory.
Then the local PATH is extended with appending the application path according to passed argument without or with an additional semicolon before.
Finally the no longer needed environment variables Separator and AppPath are deleted before exiting the subroutine.
A main mistake in main code as posted in question are the missing percent signs around environment variable HUMBER_HOME on calling batch file setEnv.bat in subdirectory bin of the directory assigned to environment variable HUMBER_HOME. This could be another reason for the error message on second execution of the batch file.
The revised code first checks if each batch file to call really exists before calling it.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
findstr /?
goto /?
if /?
pause /?
set /?
I was working on developing a batch program that would scan various sections of a PC, and log them to a file. Surprisingly, I was unable to have the program create the file to write to. I then tried to create a file, that I was fairly certain would work; it is as followed:
#echo off
ipconfig > ip.txt
timeout 5
However, this was also unable to write to the file ip.txt. I also attempted the following program, with no success.
#echo off
echo Test > test.txt
timeout 3
If anyone would be able to give advice, I would much appreciate it.
No error messages are present, and clicking the link batch file
Issue Resolved, downgraded to Win7 from Win10 and no longer experiencing the issue. Not a great fix.
ipconfig > %userprofile%\desktop\ip.txt
Use full paths. This specifies your desktop as the place to put the file.
See Set /? for help and type set to see standard variables.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's =
errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed =
to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files =
modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution =
time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 =
is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. =
Single % sign at command prompt and double % sign in a batch file.
**Batch file **I am writing batch file that takes in command line parameters and do some stuff if the parameters match. But when the run the batch file again with the new parameters, the file still runs with the old parameters.
first run : file.bat -name hello -w 400 -r 320
second run : file.bat -name hello -w 400.
When i do the second run of the file, it still performs the first run, i mean to say it still considers the parameters from the first run. Does anybody know why this is the case?
Thanks in advance.
Sorry for not posting the batch file code.
below mentioned is the code.
set filename=
set rate=
set hidden=
set rate=
:recheck
if "%1"=="-help" goto :help
if "%1"=="-name" goto :filename
if "%1"=="-h" goto :hidden
if "%1"=="-w" goto :weight
if "%1"=="-r" goto :rate
if "%~1"=="" goto :endofcommandline
:filename
shift
set filename =%1
shift
goto :recheck
For the other part of the file, I use the variable "filename" to do other stuff. I also use setlocal and endlocal at the beginning and the end of the file.
I have other corresponding labels for the each if statement and set different variables to the values passed to them if any by the user.
Sometimes, I also get echo is off when I try to print out the value of some variable.
All the variables which I use are cleared in the beginning of the file as mentioned above.
There are a couple points here.
"I also use setlocal and endlocal at the beginning and the end of the file."
"All the variables which I use are cleared in the beginning of the file as mentioned above."
Setlocal command does NOT clear the variables, it preserve current variables from posterior modification. This mean that if in a previous execution of your Batch file, or even via typed SET commands, filename variable was defined, it value remains until it is deleted or modified.
"Ok!", you said, "filename variable is modified the second time the Batch file run, Right?"
Well, no... The following line:
set filename =%1
does NOT modify "filename" variable, but "filename " instead (filename and a space). Try this:
set filename=No space
echo %filename%
set filename =Bad name with trailing space
echo %filename %
echo %filename%
You must carefully check your program to avoid this type of errors.
How can I run a command in my dos script from an input argument ?
Simplified script bla.bat:
CALL %1
Call it:
bla.bat "echo 'hello'" (or bla.bat "git status")
Error:
'"git status"' is not recognized as an internal or external command,
operable program or batch file.
It works if I do "CALL git status".
The important thing to remember is that the expanded text must look exactly like it would if you were to simply key in the command from the command line. (actually there are a few exceptions, but this is a good starting point).
To debug your script, simply put an echo before your call: #echo call %1. Now try running as you did earlier: blah.bat "echo 'hello'" produces call "echo 'hello'". Try running that from the command line - it doesn't work. You want call echo 'hello'.
One fix would be to change your script slightly: The ~ modifier strips enclosing quotes from the argument
#echo off
call %~1
Or you might be able to ditch the call and simply use the following (as long as you are not calling another batch file from which you want to return)
#echo off
%~1
If there are no other arguments on the command line, you might be better off using %* which expands to all the arguments
#echo off
%*
REM or call %*
Now you can call your batch like so
blah.bat echo "hello"
Be aware that batch has all kinds of special case weirdness that will likely require extra or different coding to work around. Too many to list - just expect the unexpected.
It looks like the problem may be that you have surrounding quotes in your input, which you'll need to stop it being broken into the different %n arguments, but try:
%~1 Which will strip any surrounding quotes from the input.
%~$PATH:1 which will strip any surrounding quotes then search within the $PATH env-var for the first match, then expand the string to include the full path to the command, which won't work for git using the windows distro because git is a batch file, and cmd would look for git status.bat
If its to be used with git, you may as well use %~1 and %~2 to call git then provide the argument to the git batch file, or call git.exe directly by modifying your $PATH. But remember that git.bat does some enviroment setup of its own before calling git itself.
I think you'll need %1% to echo the parameters. Here's my lame script which I think does what you want, works with your echo test:
bla echo hello
Gives:
C:\tmp>echo bla
bla
C:\tmp>echo echo
echo
C:\tmp>CALL echo hello
hello
echo %0%
echo %1%
CALL %*
If you want to parse through the command line arguments, let me know.
The problem is the spaces between the parameters are throwing you off (which is why you were using the quotes around git status).
Modify your bla.bat to iterate through your command line paremeters. This works for me:
SETLOCAL ENABLEDELAYEDEXPANSION
SET VAR1=
FOR %%A IN (%*) DO (
SET VAR1=!VAR1! %%A
)
call %VAR1%
ENDLOCAL
Then, run your bla.bat without the quotes around git status.
bla git status
Essentially, what this does is iterate through your command line parameters, and then executes them all as one command. The challenge comes from FOR loops in DOS not allowing you to use a variable that you're setting within itself, so you need to enable "delayed expansion" of variables. Then, the variable that you're setting needs to be encapsulated in exclamation points (not %'s). And of course, the space between !VAR1! and %%A keeps the parameters from running together in the CALL.