So I am creating a Batch Operating System, but the problem is... IT KEEPS SAYING MISSING OPERATOR!!
Here is a snippet of my code:
#echo off
title LiME - Version 1.0
mode con: cols=86 lines=21
if exist "\SystemLiME" goto startup.jsc
) else (
if not exist "\SystemLiME" goto boot.jfk
:boot.jfk
cls
echo MAINBOOTCONFIG
echo.
echo CHECKING FOR VOLUMES TO CREATE..
ping localhost -n 5 >nul
if exist "\SystemLiME" set create-vol1=0
) else (
if not exist "\SystemLiME" set create-vol1=1
if exist "\SystemLiME\pkgs" set create-vol2=0
) else (
if not exist "SystemLiME\pkgs" set create-vol2=1
if %create-vol1% == 0 set /a count-vol-create=0
if not %create-vol1% == 0 set /a count-vol-create=%count-vol-create%+=1
if %create-vol2% == 0 set /a count-vol-create=%count-vol-create%+=0
if not %create-vol2% == 0 set /a count-vol-create=%count-vol-create%+=1
echo %count-vol-create%
pause
But what I'm focusing on is this:
:boot.jfk
cls
echo MAINBOOTCONFIG
echo.
echo CHECKING FOR VOLUMES TO CREATE..
ping localhost -n 5 >nul
if exist "\SystemLiME" set create-vol1=0
) else (
if not exist "\SystemLiME" set create-vol1=1
if exist "\SystemLiME\pkgs" set create-vol2=0
) else (
if not exist "SystemLiME\pkgs" set create-vol2=1
if %create-vol1% == 0 set /a count-vol-create=0
if not %create-vol1% == 0 set /a count-vol-create=%count-vol-create%+=1
if %create-vol2% == 0 set /a count-vol-create=%count-vol-create%+=0
if not %create-vol2% == 0 set /a count-vol-create=%count-vol-create%+=1
echo %count-vol-create%
pause
Everytime I start this code, I get 'Missing operator.'
'Missing operator.'
'ECHO is off.'
'Press any key to continue...'
please help me!! :'( (btw, im new to stackoverflow :) )
Use this batch code as replacement for second posted batch code:
:boot.jfk
cls
echo MAINBOOTCONFIG
echo/
echo CHECKING FOR VOLUMES TO CREATE..
%SystemRoot%\System32\ping.exe localhost -n 5 >nul
if exist "\SystemLiME" ( set "CreateVol1=0" ) else ( set "CreateVol1=1" )
if exist "\SystemLiME\pkgs" ( set "CreateVol2=0" ) else ( set "CreateVol2=1" )
if %CreateVol1% == 0 ( set "CountVolCreate=0" ) else ( set /A "CountVolCreate+=1" )
if not %CreateVol2% == 0 set /A CountVolCreate+=1
echo %CountVolCreate%
pause
For the reason of using echo/ instead of echo. to output an empty line see DosTips forum topic
ECHO. FAILS to give text or blank line - Instead use ECHO/
Specify in batch files executables like ping with full path and with file extension to make the batch file independent on the current values of the environment variables PATH and PATHEXT.
See the answers on IF ELSE syntax error within batch file? and batch scripting - if exist ./sdcard/file.any using adb
The string after set /A is interpreted as arithmetic expression on which each whitespace/operator delimited string is interpreted automatically as variable name whose current value should be converted to a 32-bit signed integer for evaluation of the expression. Therefore it is not needed to use immediate variable expansion using %VariableName% or delayed variable expansion using !VariableName! in an arithmetic expression because just VariableName is enough even within a command block, except the variable name contains spaces or dashes or other operators.
For that reason it is not good to use variable names containing dashes when using such variables in an arithmetic expression as the dash could be interpreted as minus operator. The usage of CamelCase naming notation is in general best for variable names in batch files. Variables with CamelCase names can be easily read and searched/replaced in batch files and are surely never mixed up with text output with echo or within a remcomment line as for example on having the following command lines in a batch file:
#echo off
rem Assign batch file name to a variable.
set "BatchFileName=%~nx0"
echo Batch file name is: %BatchFileName%
set "BatchFileName="
An arithmetic expression should contain always only one equal sign. A syntax like variable=variable+=1 is definitely not right. Right is either variable=variable+1 or shorter variable+=1.
Read the answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? for an explanation why usage of set "variable=value" is recommended for the definition (or deletion) of an environment variable. On an arithmetic expression where whitespaces are just delimiters it is usually not needed to use syntax set /A "variable=expression", but there are exceptions like the one in line 9 of batch code above.
Please note that if exist "\SystemLiME" means if there is a directory or file with name SystemLiME in root of current drive. If you want to exclude file names and check for existence of a directory append a backslash on directory path. And if you want to check for existence of the directory in current directory remove the backslash at beginning of the path.
:boot.jfk
cls
echo MAINBOOTCONFIG
echo/
echo CHECKING FOR VOLUMES TO CREATE..
%SystemRoot%\System32\ping.exe localhost -n 5 >nul
if exist "SystemLiME\" ( set "CreateVol1=0" ) else ( set "CreateVol1=1" )
if exist "SystemLiME\pkgs\" ( set "CreateVol2=0" ) else ( set "CreateVol2=1" )
if %CreateVol1% == 0 ( set "CountVolCreate=0" ) else ( set /A "CountVolCreate+=1" )
if not %CreateVol2% == 0 set /A CountVolCreate+=1
echo %CountVolCreate%
pause
This batch code checks for existence of the directories SystemLiME and SystemLiME\pkgs in current directory in comparison to above batch code which checks for existence of file or directory SystemLiME and file or directory pkgs in directory SystemLiME in root of current drive.
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.
cls /?
echo /?
if /?
pause /?
ping /?
set /?
Related
I have a dynamic list of choices for a program I'm writing. I have it working correctly so that it will change the CHOICE options based on the count variable but now I'm struggling with making the errorlevel dynamic as well. Here is my code:
SETLOCAL EnableDelayedExpansion
#ECHO off
SET count=7
SET ph=
FOR /L %%a IN (1,1,%count%) DO (
SET ph=!ph!%%a
ECHO !ph!
)
CHOICE /C Q%ph%
IF errorlevel (I don't have a variable for this) (
echo "in if" & pause
)
IF errorlevel 1 echo "out of if" & pause
My idea is to set the errorlevel equal to what the user put in (e.g. the user puts in 7 as their choice, the errorlevel becomes 7) The reason I want to do this is because I need the errorlevel to pass for everything besides 1, which is reserved for a quit option (which is why I have the "Q" there) Any advice and suggestions are much appreciated! Thanks!
I suggest following batch code for this task:
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
SET count=7
SET ph=
FOR /L %%a IN (1,1,%count%) DO SET ph=!ph!%%a
%SystemRoot%\System32\choice.exe /C Q%ph%
IF NOT ERRORLEVEL 2 ECHO Bye^^!& GOTO :EOF
SET /A UserChoice=%ERRORLEVEL%-1
ECHO You have chosen %UserChoice%.
PAUSE
IF NOT ERRORLEVEL 2 means if the exit code of CHOICE is NOT GREATER OR EQUAL 2 which is the same as if LESS THAN 2 then execute ECHO and GOTO to exit processing of this batch file.
The command IF does not modify value of ERRORLEVEL as documented at
What are the ERRORLEVEL values set by internal cmd.exe commands?
It would be also possible to first assign the exit code of CHOICE to an environment variable decremented by 1 and then make the comparison for quit by comparing the value with 0.
#ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion
SET count=7
SET ph=
FOR /L %%a IN (1,1,%count%) DO SET ph=!ph!%%a
%SystemRoot%\System32\choice.exe /C Q%ph%
SET /A UserChoice=%ERRORLEVEL%-1
IF %UserChoice% == 0 ECHO Bye^^!& GOTO :EOF
ECHO You have chosen %UserChoice%.
PAUSE
It is not advisable to use an environment variable with name choice as it makes it difficult to search for this environment variable in a batch file containing also external command CHOICE which is the reason for using UserChoice.
The command CHOICE is specified with full qualified file name (file path + file name + file extension) for safety reasons. Windows command processor does not need to search for choice.* with a file extension listed in environment variable PATHEXT in current directory and the directories listed in local environment variable PATH on using full qualified file name. This makes the batch file robust against corrupted system PATH containing the path of a folder before most important folder path %SystemRoot%\System32 which by chance contains also a choice.* file with a file extension listed in PATHEXT. The local environment variable PATH does not need to exist at all on running this batch file because of using full qualified file name of executable CHOICE. It also does not matter with full qualified file name if a user created a batch file with name choice.bat or choice.cmd in the directory being the current directory on running this batch file or any other directory in PATH being searched by cmd.exe before %SystemRoot%\System32.
To solve my issue I used the NEQ and EQU statements that I was not aware would work with errorlevel. I also incorporated the suggestion of #LotPings to get this code as a result which works great! To technically save the user input as a variable, I just subtracted one from the choice variable and it equals the same.
SETLOCAL EnableDelayedExpansion
REM #ECHO off
SET count=7
SET ph=
FOR /L %%a IN (1,1,%count%) DO (
SET ph=!ph!%%a
REM ECHO !ph!
)
CHOICE /C Q%ph%
set choice=%errorlevel%
ECHO %choice%
IF %choice% NEQ 1 (
ECHO "not equal" & PAUSE
SET /A choice=choice-1
ECHO !choice! REM This is now the value the user inputted.
PAUSE
)
IF %choice% EQU 1 ECHO "equal" & PAUSE
I am facing a problem with my following batch script, where I can see how the execution of the command %nr% --f !path2! never seems to happen and I don't understand the reason.
What am I doing wrong? Too many nested conditions ?
EDIT: adding WRONG code where comments are enabled
rem The call to this batch script will be this
rem C:/Projects/DevelopmentTools/SDKs/TP/B/Scrpt/Exg_Serial_Flasher.bat EF.hex DH.hex C:/Projects/DevelopmentTools/SDKs/TP/B/E/Output/CN/Exe/
setlocal enabledelayedexpansion
set nr=nr.exe
if "%1"=="" (
if "%2"=="" (
if "%3"=="" (
echo "[Error]"
set "runScript="
)
)
) else (
set "input1=%1"
set "input2=%2"
set "path3=%3%nr%"
set "myPath"=%3"
set "path1=!myPath!!input1!"
set "path2=!myPath!!input2!"
rem Control variable
set "runScript=true"
)
if defined runScript (
if exist "%path3%" (
%nr% --check
if exist !path1! (
%nr% --f !input1!
echo !ERRORLEVEL!
if !ERRORLEVEL! EQU 0 (
echo !input1! set correctly
if exist !path2! (
echo Setting !exgSerial!
%nr% --f !input2!
if !ERRORLEVEL! EQU 0 (
echo Everything went fine
)
)
)
)
)
)
Thanks!
I suggest following batch code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ExeFile=nr.exe"
if "%~1" == "" goto ArgumentError
if "%~2" == "" goto ArgumentError
if not "%~3" == "" goto ProcessArguments
:ArgumentError
echo Error: %~nx0 must be called with three arguments.
exit /B 1
:ProcessArguments
rem Assign third argument to an environment variable.
set "FilePath=%~3"
rem Replace forward slashes by backslashes which is the directory separator on Windows.
set "FilePath=%FilePath:/=\%"
rem Make sure the file path ends with a backslash.
if not "%FilePath:~-1%" == "\" set "FilePath=%FilePath%\"
set "HexFile1=%FilePath%%~1"
set "HexFile2=%FilePath%%~2"
set "ExeFile=%FilePath%%ExeFile%"
if not exist "%ExeFile%" echo Error: "%ExeFile%" does not exist. & exit /B 2
if not exist "%HexFile1%" echo Error: "%HexFile1%" does not exist. & exit /B 3
if not exist "%HexFile2%" echo Error: "%HexFile2%" does not exist. & exit /B 3
"%ExeFile%" --check
"%ExeFile%" --f "%HexFile1%"
if errorlevel 1 echo Error: Processing "%HexFile1%" failed. & exit /B 4
"%ExeFile%" --f "%HexFile2%"
if errorlevel 1 echo Error: Processing "%HexFile2%" failed. & exit /B 4
echo Everything worked fine.
endlocal
An error condition is detected as soon as possible with resulting in exiting batch file processing with an appropriate error message and exit code.
There is no need for delayed environment variable expansion which makes processing the batch file faster and avoids problems with directory or file names containing an exclamation mark.
Name of a file or the file path can contain also command line critical characters like space or one of these characters &()[]{}^=;!'+,`~.
There are no nested IF conditions making successful execution flow straight from top to bottom.
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 /? ... explains %~1 which expands to argument 1 with removing any surrounding quotes.
echo /?
endlocal /? ... used here implicit on exiting batch file processing with exit and explicit at end of batch file.
exit /?
goto /?
if /?
rem /?
setlocal /?
See also Single line with multiple commands using Windows batch file.
I think I found the issue, it has to do with the fact that the "echos" to debug seem to influence the script execution. So in the code of my question, if I enable the echos, the script will fail running whereas if I disable them( commented out as below), the script does work.
Nevertheless, I don't understand why it does fail with the echos in first instance.
Code with disabled echos and working
rem The call to this batch script will be this
rem C:/Projects/DevelopmentTools/SDKs/TP/B/Scrpt/Exg_Serial_Flasher.bat EF.hex DH.hex C:/Projects/DevelopmentTools/SDKs/TP/B/E/Output/CN/Exe/
setlocal enabledelayedexpansion
set nr=nr.exe
if "%1"=="" (
if "%2"=="" (
if "%3"=="" (
echo "[Error]"
set "runScript="
)
)
) else (
set "input1=%1"
set "input2=%2"
set "path3=%3%nr%"
set "myPath"=%3"
set "path1=!myPath!!input1!"
set "path2=!myPath!!input2!"
rem Control variable
set "runScript=true"
)
if defined runScript (
if exist "%path3%" (
%nr% --check
if exist !path1! (
%nr% --f !input1!
rem echo !ERRORLEVEL!
if !ERRORLEVEL! EQU 0 (
rem echo !input1! set correctly
if exist !path2! (
rem echo Setting !exgSerial!
%nr% --f !input2!
if !ERRORLEVEL! EQU 0 (
echo Everything went fine
)
)
)
)
)
)
I'm making a Minecraft modding tool using a batch file. But on execution of the batch file the Windows command interpreter outputs the syntax error message:
) was unexpected
I can't figure out why.
This is my code:
#echo off
cd mods
setlocal enabledelayedexpansion
set "selected=1"
call:print 1
call:print 2
:menu
choice /c wse>nul
if "%errorlevel%"=="2" (
if not !selected! GEQ !a! (
set /a "selected+=1"
cls
call:print 1
call:print 2
)
)
if "%errorlevel%"=="1" (
if not !selected!==1 (
set /a "selected-=1"
cls
call:print 1
call:print 2
)
)
if "%errorlevel%"=="3" (
)
goto menu
:print
if "%1"=="1"set a=0
echo.
if "%1"=="1" (
echo Uninstalled:
) else (
echo Installed:
)
echo.
for %%f in (*.jar) do (
if "%1"=="1" (
if NOT EXIST
"C:/Users/Coornhert/AppData/Roaming/.minecraft/mods/%%~nf.jar" (
set /a "a+=1"
if "!a!"=="!selected!" (
echo -%%~nf
) else (
echo %%~nf
)
set "b=!a!"
)
) else (
if EXIST "C:/Users/Coornhert/AppData/Roaming/.minecraft/mods/%%~nf.jar" (
set /a "a+=1"
if "!a!"=="!selected!" (
echo -%%~nf
) else (
echo %%~nf
)
set "b=!a!"
)
)
)
goto :eof
And it works, but when I hit s, execution terminates with the error message.
Folder structure of folder containing the batch file:
mods
Foo.jar
Foo2.jar
Folder structure of target folder:
C:\Users\Coornhert\AppData\Roaming\.minecraft\mods
Foo.jar
I partly do not understand what this batch file should do, but here is the batch file rewritten with several improvements.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem cd /D "%~dp0mods"
pushd "%~dp0mods"
set "a=0"
set "selected=1"
call :PrintIt 1
call :PrintIt 2
:Menu
choice /C wse /N
if errorlevel 3 popd & endlocal & goto :EOF
if errorlevel 2 goto AddOne
if %selected% == 1 goto Menu
set /A selected-=1
cls
call :PrintIt 1
call :PrintIt 2
goto Menu
:AddOne
if %selected% GEQ %a% goto Menu
set /A selected+=1
cls
call :PrintIt 1
call :PrintIt 2
goto Menu
:PrintIt
if %1 == 1 set "a=0"
echo/
if %1 == 1 (echo Uninstalled:) else echo Installed:
echo/
for %%I in (*.jar) do (
if %1 == 1 (
if not exist "%APPDATA%\.minecraft\mods\%%~nI.jar" (
set /A a+=1
if !a! == %selected% (echo -%%~nI) else echo %%~nI
set "b=!a!"
)
) else (
if exist "%APPDATA%\.minecraft\mods\%%~nI.jar" (
set /A a+=1
if !a! == %selected% (echo -%%~nI) else echo %%~nI
set "b=!a!"
)
)
)
goto :EOF
It does nothing useful as is, but batch code in question is also not useful at all.
The applied improvements are:
The command SETLOCAL is moved to top of file. The reason is:
It pushes path of current directory on stack.
It pushes state of command extensions on stack.
It pushes state of delayed expansion on stack.
It pushes the memory address of the current environment variables table on stack.
It creates a copy of the current environment variables table in memory and makes this new environment variables table active.
It sets command extensions and delayed expansion according to the specified parameters if the command is called with parameters at all.
The command ENDLOCAL is executed before leaving batch file. The reason is:
It deletes the current environment table which means no environment variable defined in this batch file exists anymore after ENDLOCAL except it existed already before execution of command SETLOCAL.
It pops memory address of previous environment table from stack and uses this address resulting in restoring initial environment variables.
It pops state of delayed expansion from stack and disables/enables delayed expansion accordingly.
It pops state of command extensions from stack and disables/enables command extensions accordingly.
It pops previous current directory path from stack and sets current directory to this path to restore the current directory.
So the entire command process environment is restored on exit of this batch file to exactly the same environment as it was on starting the batch file.
This makes it possible to call this batch file from within another batch file or from within a command prompt window with no impact on calling batch file or command process.
The command CD could be extended to include drive and path of argument 0 which is the full path of the batch file ending with a backslash because the subdirectory mods is most likely always expected in directory of the batch file and it should not matter what is the current directory on running the batch file.
But cd /D "%~dp0mods" could fail if the batch file is located on a network share accessed using UNC path and therefore command PUSHD is used instead working with enabled command extensions also for UNC paths.
In all programming and scripting languages it is required that variables are defined and initialized with a value before being used the first time. For that reason the environment variables a and selected are defined at top of the batch file with default values. By the way: a is a very bad name for a variable. Why? Search for a in batch file. It is quite often found on not using special find features like whole word only, isn't it.
PRINT is a command as it can be seen on running in a command prompt window print /?. While it is possible to use command names as labels or as names for subroutines, it is not advisable to do so as it could be confusing for readers of the batch file.
The command CHOICE has the option /N to hide the list of choices in the prompt. It is better to use this option than redirecting the output of CHOICE to device NUL.
The very old but still valid Microsoft support article Testing for a Specific Error Level in Batch Files explains that if errorlevel X means that the condition is true if the exit code of previous command or application is greater or equal X. The command CHOICE with 3 choices exits always with 1, 2 or 3 as exit code. So it is best to use:
if errorlevel 3 rem Do something on third choice avoiding fall through to next line.
if errorlevel 2 rem Do something on second choice avoiding fall through to next line.
Do something on first choice.
The advantage of using this method is that it even works with CHOICE within a command block on which if %ERRORLEVEL% == X fails because of delayed expansion would be required and usage of if !ERRORLEVEL! == X.
The integer comparison if %selected% GEQ %a% would not work if the two arguments would be enclosed in double quotes as the double quotes are also interpreted as part of the arguments to compare. For that reason using if "%selected%" GEQ "%a%" would result in running a string comparison instead of an integer comparison. For more information about comparing values with IF look on answer on Exit a for loop in batch.
It is safe here to omit the double quotes also on the other IF conditions with == operator running string comparisons because the environment variables selected and a must be both defined before running this IF condition and therefore both variables are defined at top of the batch file.
The answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains why set "variable=value" should be always used to assign a value to an environment variable or delete an environment variable on omitting the value. And this answer also explains why on set /A variable=expression the double quotes can be usually omitted as whitespace characters are interpreted completely different within an arithmetic expression. The exception is usage of set /A with 1 or more commands on same command line on which double quotes around variable=expression would be also needed.
The batch file should be exited when the batch file user enters e or E to take third choice. This could be done with just goto :EOF, or with exit /B which is an alias for goto :EOF, or with just exit which always exits entire command process independent on calling hierarchy which is not recommended. Windows command interpreter would implicitly restore the initial stack before finishing batch file execution. But it is nevertheless good coding practice to pop from stack with code which was pushed on stack before with code. For that reason there is used popd & endlocal & goto :EOF. See answer on Single line with multiple commands using Windows batch file for more information about usage of multiple commands on one command line.
The list of predefined environment variables of used user account is output on running in a command prompt window the command set. One predefined Windows environment variable is APPDATA with path to application data of current user account. This environment variable should be used instead of a fixed path to application data directory of user account.
And the directory separator on Windows is the backslash character \ and not slash character / as on Unix and Mac.
The usage of f as loop variable is not recommended as this is also a loop variable modifier. %%~f can be interpreted by Windows command interpreter as value of loop variable f without surrounding double quotes or as incomplete loop variable reference because of missing loop variable after %%~f which could be also interpreted as full file name of ?. So it is better to use # or $ as loop variable or upper case letters to avoid such a confusion on interpreting the loop variable reference. Loop variables are case-sensitive.
I prefer for IF conditions with an ELSE branch the coding style
if condition (
command
) else (
command
)
But here in this batch file with command being just a short ECHO command the code is better readable on being more compact with using:
if condition (echo short message) else echo other short message
Delayed expansion for an environment variable referenced within a command block started with ( and ending with matching ) is only needed if the environment variable is also modified in same command block. Therefore environment variable a must be referenced in body of FOR with usage of delayed expansion while environment variable selected can be referenced as usual because of not modified within this command block at all.
It is better to use echo/ to output an empty line instead of echo.. For the reason read the DosTips forum topic: ECHO. FAILS to give text or blank line - Instead use ECHO/
For a basic understanding of the used commands, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
choice /?
cls /?
echo /?
endlocal /?
for /?
goto /?
if /?
popd /?
pushd /?
rem /?
set /?
setlocal /?
Been wrecking my brain all night trying to figure out why this isn't working, but one of my variables isn't releasing on the next iteration of my loop and I can't figure out why... The first pass of the loop seems to work fine, but the next iteration, the first variable gets locked and the script connects to the system that's already been configured.
I've been staring at this for a while now and no matter how I approach it, it still behaves badly. :/ The purpose is to read a text-string of a given file, and use it to modify (via Find and Replace (fnr.exe)) another file with several instances of the required data. I didn't have alot of luck with 'findstr' replacing so many instances of the text required so I went with a tool I've used before that seemed to work really well in it's previous scripting application...
Truth be told, I find myself stumbling with even the most basic code a lot of times, so any kind soul willing to impart some wisdom/assistance would be greatly appreciated!
Thanks in advance...
#ECHO ON
setlocal enabledelayedexpansion
> "%~dp0report.log" ECHO Batch Script executed on %DATE% at %TIME%
rem read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
SET lwn=
SET WKSTN=%%A
rem connect to workstation and read lwn.txt file
pushd "\\%WKSTN%\c$\"
IF ERRORLEVEL 0 (
FOR /F %%I in (\\%wkstn%\c$\support\lwn.txt) DO (
SET LWN=%%I
%~dp0fnr.exe --cl --dir "\\%WKSTN%\c$\support\folder\config" --fileMask "file.xml" --find "21XXXX" --replace "%%I"
IF ERRORLEVEL 0 ECHO Station %LWN%,Workstation %WKSTN%,Completed Successfully >> %~dp0report.log
IF ERRORLEVEL 1 ECHO Station %LWN%,Workstation %WKSTN%, A READ/WRITE ERROR OCCURRED >> %~dp0report.log
echo logwrite error 1 complete
popd
)
)
IF ERRORLEVEL 1 (
ECHO ,,SYSTEM IS OFFLINE >> %~dp0report.log
)
popd
set wkstn=
set lwn=
echo pop d complete
)
msg %username% Script run complete...
eof
The ! notation must be used on all variables that are changed inside the loop.
C:>type looptest.bat
#ECHO OFF
setlocal enabledelayedexpansion
rem read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
SET WKSTN=%%A
ECHO WKSTN is set to %WKSTN%
ECHO WKSTN is set to !WKSTN!
pushd "\\!WKSTN!\c$\"
ECHO After PUSHD, ERRORLEVEL is set to %ERRORLEVEL%
ECHO After PUSHD, ERRORLEVEL is set to !ERRORLEVEL!
IF !ERRORLEVEL! NEQ 0 (
ECHO ,,SYSTEM IS OFFLINE
) ELSE (
ECHO Host !WKSTN! is available
)
popd
)
EXIT /B 0
The workstations.txt file contained the following. (I should not give out actual host names.)
LIVEHOST1
DEADHOST1
LIVEHOST2
The output is...
C:>call looptest.bat
WKSTN is set to
WKSTN is set to LIVEHOST1
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 0
Host LIVEHOST1 is available
WKSTN is set to
WKSTN is set to DEADHOST1
The network path was not found.
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 1
,,SYSTEM IS OFFLINE
WKSTN is set to
WKSTN is set to LIVEHOST2
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 0
Host LIVEHOST2 is available
Although your code have several issues, the main one is the use of % instead of ! when you access the value of variables modified inside a for loop (although you already have the "enabledelayedexpansion" part in setlocal command). However, I noted that you sometimes use the FOR replaceable parameter (like in --replace "%%I") and sometimes you use the variable with the same value (%LWN%), so a simpler solution in your case would be to replace every %VAR% with its corresponding %%A for parameter.
I inserted this modification in your code besides a couple small changes that make the code simpler and clearer.
#ECHO ON
setlocal
> "%~dp0report.log" ECHO Batch Script executed on %DATE% at %TIME%
rem Read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
rem Connect to workstation and read lwn.txt file
pushd "\\%%A\c$\"
IF NOT ERRORLEVEL 1 (
FOR /F "usebackq" %%I in ("\\%%A\c$\support\lwn.txt") DO (
%~dp0fnr.exe --cl --dir "\\%%A\c$\support\folder\config" --fileMask "file.xml" --find "21XXXX" --replace "%%I"
IF NOT ERRORLEVEL 1 (
ECHO Station %%I,Workstation %%A,Completed Successfully >> %~dp0report.log
) ELSE (
ECHO Station %%I,Workstation %%A, A READ/WRITE ERROR OCCURRED >> %~dp0report.log
echo logwrite error 1 complete
)
)
) ELSE (
ECHO ,,SYSTEM IS OFFLINE >> %~dp0report.log
)
popd
echo pop d complete
)
msg %username% Script run complete...
I never wrote a batch file, and now I have to write a batch file that runs a command line and parse its output. (e.g: CMD: Diskpart List volume, Output: list of volumes and the free space, I want to find the volume with the maximum free space)
My questions:
what should I write to get the output?
How can I parse it?
Thanks you all,
DiskPart list volumes will not give you free space, but I assume that was only an example.
This batch will give you drive with maximum capacity on your system.
It uses enough constructs to get you going with your own requirements...
You will need to put the following into a batch file
#echo off
echo ****************************************************
echo *** Give maximum drive size on a given system ****
echo ****************************************************
echo *** This script shows various batch constructs. ****
echo *** Use at your own risk - no warranty given ****
echo *** that's fit for any intended purpose :-)) ****
echo *** or that it's error free ****
echo ****************************************************
echo.
REM All of our vars will be local - we do not want to pollute environment. For more info exec 'help setlocal' from cmdline
REM implied endlocal will be issued at the end, no need to insert it
setlocal
REM name of temp file we will use
set tmpFile=tmp.txt
REM power will store multiplier we are currently working in
set power=0
REM maximum found drive size
set maxSize=0
REM Enable delayed expansion - must be on, otherwise all vars will be expanded on input. For more info exec 'help setlocal' from cmdline
setlocal enabledelayedexpansion
REM enable extensions (on by default). Please see help setlocal
setlocal enableextensions
REM get input from user. For more info exec 'help set' from cmdline
set /P cmd=Give diskpart command you want to run [list volume]
REM set default command if user did not set anything
if NOT DEFINED cmd set cmd=list volume
REM set file to contain command we want to run
echo %cmd%>%tmpFile%
REM Skip 8 first lines, then read each line as token. For more info exec 'help for' from cmdline
REM use of backquote will enable us to use temp file with spaces in name
set ERRORLEVEL=0
for /f "tokens=* skip=8 usebackq" %%i in (`diskpart /s %tmpFile%`) do (
set line=%%i
REM read 5 chars from input token, starting at char 49, convert it to number and assign to env var. For more info exec 'help set' from cmdline
REM This also shows delayed expansion convention (!var!).
set /A tsize=!line:~49,5!*1
REM test for unequality (we want to run body only if given size is not 0). For more info exec 'help if' from cmdline
REM see also other operators used (LSS, GEQ
if !tsize! NEQ 0 (
REM it's not possible to do most obvious (multiplication) as this would overflow.
REM '(' is block character. Look how they are positioned, it has to be this way!
REM Mind also where you can put spaces!
REM 'set a=7' is different to 'set a=7 '
set unit=!line:~54,2!
REM Mind use of '
if '!unit!'==' B' (
if !power! LSS 1 (
set power=1
set maxSize=!tSize!
)
if !power!==1 (
if !tsize! GEQ !maxsize! (
set maxSize=!tsize!
set maxUnit=!unit!
set maxDrive=!line!
)
)
)
if !unit!==KB (
if !power! LSS 3 (
set power=3
set maxSize=!tSize!
)
if !power!==3 (
if !tsize! GEQ !maxsize! (
set maxSize=!tsize!
set maxUnit=!unit!
set maxDrive=!line!
)
)
)
if !unit!==MB (
if !power! LSS 6 (
set power=6
set maxSize=!tSize!
)
if !power!==6 (
if !tsize! GEQ !maxsize! (
set maxSize=!tsize!
set maxUnit=!unit!
set maxDrive=!line!
)
)
)
if !unit!==GB (
if !power! LSS 9 (
set power=9
set maxSize=!tSize!
)
if !power!==9 (
if !tsize! GEQ !maxsize! (
set maxSize=!tsize!
set maxUnit=!unit!
set maxDrive=!line!
)
)
)
)
)
REM cleanup
del %tmpFile% /Q
REM this prints empty line
echo.
echo Your max drive is: !maxSize! !maxUnit!
echo.
echo Drive details:
echo !maxDrive!
Here's the easy beginning bit.
echo list volume > %temp%\temp12345
diskpart /s %temp%\temp12345 > %temp%\diskpart.txt
Doing this in batch is a nightmare, do you have any other options?
Edit: To do it in batch, you need to use FOR.
Check For /? for examples on how to parse data.