String comparison in for loop? (specifically in TC) - loops

I want to take a bunch of files in folder, and do something if the file doesn't contain the word Microsoft.
I am working in Teamcity, but except for the amount of % before variables should be the same as batch files.
setlocal enabledelayedexpansion
for /r %%%%v in (*.dll) do (
REM Do something that cif fails changes the errorlevel
echo !errorlevel!
set filename = %%%%~nv
echo !filename!
if !filename:Microsoft!==!filename! (
if !errorlevel! neq 0 goto :error
)
)
When I echo the errorlevel I get the correct result, however the filename echo isn't working, which implies I didn't set it correctly. Of course then the comparison is meaningless (it never gets into the if block).
What am I doing wrong?

So the comments on my question were really all I needed, thanks!
In any case, if anyone else encounters this, here's the code that works:
setlocal enabledelayedexpansion
for /r %%%%v in (*.dll) do (
set filename=%%%%~nv
REM Do something that if fails changes the errorlevel
if !errorlevel! neq 0 if /i "!filename:Microsoft=!"=="!filename!" (
goto :error
)
)
Please note the thing to be careful is not to do anything that might change the errorlevel before using it, including echoing it...

Related

Batch file cannot re-assign value in loop

I want to make the batch file that checking the account information.
Within below codes, I need 2,3,4 line from "net accounts" command outputs, and each line needs the individual process.
For to do this, I use the 'cnt' variable, and increase to checking.
However, 'cnt' doesn't increase at #1.
Why this happened, and how to solve it?
#echo off
SETLOCAL EnableDelayedExpansion
net accounts > accountInfo.txt
set cnt=0
echo """"""""""""""""""""""""""
for /f "tokens=1* delims=:" %%G in (accountInfo.txt) do (
ECHO.%%G | FIND /I "mum">Nul && (
SET var=%%~nH
Set myvar=!var!
set myvar=!myvar: =!
echo %%G !myvar!
echo %cnt%
set /A cnt+=1 ---------- here! #1
) || ( ECHO. )
)
echo """"""""""""""""""""""""""
ENDLOCAL
pause
You are using DelayedExpansion everywhere else in your code. Why not there as well?
Just change echo %cnt% to echo !cnt! and you should be fine.
Reason for that is that in batch blocks of code beeing surrounded by parenthesis are calculated at once. To see the updated value use DelayedExpansion as said above.

How to use findstr within a loop?

I am trying to read the filename and according to the filename set the Output variable.
I have tried using findstr directly on %%F (findstr /i "M002" %%F >nul 2>&1 ) and also writing to a temp text file (as below) to test and read it, but nothing worked.
What I'm doing wrong?
P.S. If I remove this out from the loop the code works, but I need it within the loop due to the last line.
rem ===========================================
set FileType=pdf
for %%F in (%~dp0*.%FileType%) do (
rem ECHO %%F
echo "%%F" > test.txt
findstr /i "M002" test.txt >nul 2>&1
echo %errorlevel%
if not %errorlevel% == 0 (
echo "4pp"
echo %%F
set Output=4PP
) ELSE (
echo "Letter"
echo %%F
set Output=Letter
)
set NetComm="XYZ" "%Output%" etc etc etc
)
rem ====================================
Generation 5,961 of delayedexpansion.
Batch parses the entire statement from the for through to the last closing parenthesis and replaces any %var% with the value of that variable at the time the statement is parsed.
Consequently, attempting to use a value which is established within the loop will fail. This applies to %output% and %errorlevel% in the current instance.
Dealing with %errorlevel% is easy. The syntax
if errorlevel n
works on the run-time value of errorlevel and is true if errorlevel has been set to n or greater than n.
Personally, I find the if not condition ... else clumsy. I can't see why it's so common. Fuzzy thinking in my book...
There are three common ways to overcome the problem, each has its own advantages and disadvantages, proponents and critics.
First, the "documented" method. Use a setlocal enabledelayedexpansion instruction. Once this instruction has been executed, !var! will access the current value and %var% the initialvalue ofvar`.
Second, the subroutine method. CALL :sub within a loop executes a subroutine (see the documentation - call /? from the prompt) and within that subroutine, %var% will have the value as established within the loop.
Third, it's sometimes possible to use call echo %%var%% (or call someotherinsruction) where the call is executiong the target as if it was a subroutine.
Hence, in your case, a fix might be
rem ===========================================
set FileType=pdf
for %%F in (%~dp0*.%FileType%) do (
rem ECHO %%F
findstr /i "M002" "%%F" >nul 2>nul
CALL echo %%errorlevel%%
if errorlevel 1 (
echo "4pp"
echo %%F
set Output=4PP
) ELSE (
echo "Letter"
echo %%F
set Output=Letter
)
CALL set NetComm="XYZ" "%%Output%%" etc etc etc
)
rem ====================================
depending entirely on your definition of "works" (which is not an absolute - it has meaning only to you.)

add the condition statement to check directory existence. batch scripting

I need to add in a conditional statement to check for a folder so that it can exexute the below script. Lets say the script is placed in folder c:/temp/A but I want the script to excute and change the file extensions of files in a another directory d:/xxx/B. If directory B doesnt exists, throw an error and exit. I tried using if else statement but its says no else statement is allowed. Please help me out and let me know how it can be done.
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%F in (*.*_error* *.*error_*) do ( set "ext=%%~xF"
SET "ext=!ext:_error=!"
ren "%%F" "%%~nF!ext:error_=!"
)
You can do a condition like this.
IF EXIST "D:\xxx\b\" (goto thescript) else goto theerror
:thescript
#then whatever you want to run here.
goto :EOF
:theerror
ECHO File does not exist
goto :EOF
#echo off
setlocal ENABLEDELAYEDEXPANSION
PUSHD d:\xxx\B 2>nul
if errorlevel 1 (
echo required destination not found
goto :wherever
)
for %%F in (*.*_error* *.*error_*) do ( set "ext=%%~xF"
SET "ext=!ext:_error=!"
ren "%%F" "%%~nF!ext:error_=!"
)
POPD
Best idea to use the correct character for directoryname-separators. / is used for switches.

Batch function not working correctly

A while ago I made a function that you can call from the command prompt or any batch file (it was just for fun, I don't see how it could be useful). It basically just makes your (Microsoft) computer speak whatever you wrote in as the parameter.
I recently got some inspiration to add a switch to it where it would read the contents of a file. My standalone script worked, but when I added it to my function, it didn't work as I would have liked.
Here's the code:
#echo off & setlocal enabledelayedexpansion
if "%~1"=="/?" (
echo.
echo TALK "Text" [Parameters]
echo.
echo Text - The phrase you want to be spoken.
echo.
echo [Parameters]:
echo /f - Read the contents of a file. "Text" changes to the file path.
echo.
endlocal
exit /b
)
if "%~2 X" equ "/f X" (
if not exist %~1 (
echo File does not exist or cannot be found.
endlocal
exit /b
)
set cont=
for /f "delims=" %%i in (%~1) do set cont=!cont! %%i
:b
echo Set a = Wscript.CreateObject("SAPI.SpVoice") > "Talk.vbs"
echo a.speak "%cont%" >> "Talk.vbs"
start /WAIT Talk.vbs
del Talk.vbs
endlocal
exit /b
)
set text=%~1
echo set speech = Wscript.CreateObject("SAPI.spVoice") > "talk.vbs"
echo speech.speak "%text%" >> "talk.vbs"
start /WAIT talk.vbs
del Talk.vbs
endlocal
exit /b
Unfortunately I don't have working function code (before I added the /f switch).
This is a last resort for me as I've edited it heavily and scoured the code for any give away as to what the problem might be.
Another bad thing is that I didn't take note of what I changed, so I can't exactly tell you what I've tried. I can tell you what the outputs are though.
The first time I tried, it gave the output The syntax of the command is incorrect.
It's now at the point where the original function (just converting text to speech) doesn't work anymore. The contents of the file Talk.vbs (which was made during the process) is a.speak "".
I'll keep updating my attempts, but knowing me it's something really simple that I've overlooked.
--EDIT--
At the suggestion of someone, I put carats before the square brackets in the syntax section. Nothing changed.
Along with escaping the parenthesis you also had to surround if exist %~1 in quotes in case of a argument of "some words I want it to say". Also cleaned it up a bit. Code at the bottom, but first an explanation.
If you looked at talk.vbs before it was deleted you would see this:
a.speak "!cont! contents of the file here"
This is because of this code:
for /f "delims=" %%i in (%~1) do set cont=!cont! %%i
:b
echo Set a = Wscript.CreateObject("SAPI.SpVoice") > "Talk.vbs"
If you turned echo on and watched the code you would see the last unescaped ) was taking the contents of the for loop and including it in the redirect.
Corrected and cleaned code:
#echo off & setlocal enabledelayedexpansion
if "%~1"=="/?" (
echo.
echo TALK "Text" [Parameters]
echo.
echo Text - The phrase you want to be spoken.
echo.
echo [Parameters]:
echo /f - Read the contents of a file. "Text" changes to the file path.
echo.
endlocal
exit /b
)
set text=
if [%2]==[/f] (
if exist "%~1" (
for /f "usebackq delims=" %%i in (%1) do set text=!text! %%i
) else (
endlocal
exit /B
)
)
if [%2]==[] set text=%~1
echo set speech = Wscript.CreateObject^("SAPI.spVoice"^) > "talk.vbs"
echo speech.speak "%text%" >> "talk.vbs"
cscript //NoLogo //B talk.vbs
del Talk.vbs
endlocal
exit /b
Edit: fixed the for statement pointed out by Andriy M
In your echo statements that contain parentheses, try escaping the parentheses with carats. I suspect especially the echo within the if statement is partially getting evaluated literally.
One other minor suggestion, I would also replace
start /WAIT Talk.vbs
with
cscript /nologo Talk.vbs
It's not that I think the start /wait is causing the error, but it does cause a second console window to appear temporarily for no good reason -- or it will whenever your script executes that far, anyway.
I made a few other suggested changes here, such as eliminating the need for a /f switch. If "%1" is the name of a file that exists, read it. Otherwise, treat it as text to read. And instead of having a separate subroutine for reading a file versus getting text from input, all that needs to happen is a variable has a different value.
#echo off & setlocal enabledelayedexpansion
if "%1"=="/?" ( goto usage )
if "%1"=="" ( goto usage )
if "%1"=="--help" ( goto usage )
if exist "%1" (
set txt=
for /f "usebackq tokens=*" %%i in (%1) do set txt=!txt! %%i
) else (
set txt=%1
)
echo Set a = Wscript.CreateObject^("SAPI.SpVoice"^) > "talk.vbs"
echo a.speak "%txt%" >> "talk.vbs"
cscript /nologo talk.vbs
del talk.vbs
endlocal
goto :EOF
:usage
echo.
echo TALK ["text"^|filename]
echo.
echo talk filename -- speaks the contents of filename
echo talk "text" -- speaks the supplied text
endlocal
goto :EOF

Batch file ErrorLevel woes

I am writing a batch file to upgrade some systems. I need to parse a date from an xml file and save it for use later in the file. The format of the date is yyyy\MM\dd.
What I have so far is:
#echo off
setLocal DisableDelayedExpansion
for /f "tokens=* delims= " %%G in (ConnectionManagement.xml) do (
set str=%%G
set mydate=%%G
echo got-
echo %%G
echo %mydate%
PAUSE
ECHO %mydate%|findstr /R /C:[0-9][0-9][0-9][0-9]\\[0-9][0-9]\\[0-9][0-9] > nul
IF ERRORLEVEL 0 goto valueok
)
echo DONE
PAUSE
goto end
:valueok
echo VALUEOK
:end
PAUSE
Unfortunately this incorrectly recognised the xml header as a valid date; but I think this is to do with ErrorLevel being reset (?). mydate isn't being set, and it recognises the empty variable mydate as a match (!!??). The output is:
got-
<?xml version="1.0" encoding="utf-8"?>
ECHO is off.
Press any key to continue . . .
VALUEOK
Press any key to continue . . .
...
Getting rather desperate for a solution. thanks...
ErrorLevel is not being reset. What is actually happening is that IF ERRORLEVEL 0 does not behave the way you expect. Basically, the test is not "Does errorlevel equal 0?", its "Is errorlevel greater than or equal to zero?". Given this, it should be clear that IF ERRORLEVEL 0 will always be true (at least, if you only expect positive errors...)
Therefore, you need to use IF NOT ERRORLEVEL 1 goto valueok instead.
As RB wrote, IF ERRORLEVEL 0 does not behave the way you expect.
The if errorlevel is a special IF-case.
To use a normal IF-construct you could use
setlocal EnableDelayedExpansion
...
FOR-LOOP .. DO (
if !ERRORLEVEL! EQU 0 goto valueok

Resources