My goal is to compare say the contents of one txt file to the contents of all text files on a specific folder, if ANY txt files match then do one set of processes if none match then do another set.
I've tried doing the below:
#echo off
:main
fc "C:\Users\degibson\Desktop\test\*.txt" "C:\Users\degibson\Desktop\test2\temp1.txt" > NUL
if errorlevel 1 goto error
:next
echo do some important task
pause
:error
echo do some other important task
pause
Problem - This only works if ALL the files matched temp1.txt contents.
Is there a better way to accomplish this task?
You can use the FOR command to iterate all text files in the directory. I would then suggest you use the CALL command instead of GOTO because CALL will return execution to the FOR command whereas the GOTO will break the FOR command execution. The execution returns to the FOR command by using the builtin :EOF label to end the current called process. You could also use EXIT /B.
#ECHO OFF
:main
FOR %%G IN (C:\Users\degibson\Desktop\test\*.txt) DO (
fc "%%G" "C:\Users\degibson\Desktop\test2\temp1.txt" >NUL
if errorlevel 1 (
CALL :error
) ELSE (
CALL :next
)
)
GOTO :EOF
:next
echo do some important task
pause
GOTO :EOF
:error
echo do some other important task
pause
GOTO :EOF
Related
For searches in Windows Registry using batch scripting, I have to loop through a few keys, make a comparison to determine which is the right one, and then update the key.
Iteration in a for loop seems impossible to break out of. I have seen that others are facing similar issues but there does not seem to be a simple solution. Here is a snippet that demonstrates the issue.
#echo off
echo.
echo Diet Favorites
set favorite="bananas"
for %%a in (apples, bananas, chocolates) do call :reviewList %%a
echo.
echo Processing completed.
goto end
:reviewList item
set foundFavorite="false"
call :chooseFavorite "%~1"
if /I "%foundFavorite%"=="true" (
echo found the favorite - %~1
exit /b 0
) else (
echo skip %~1
)
endlocal & goto :eof
:chooseFavorite item
if "%~1"==%favorite% set "foundFavorite=true"
endlocal & goto :eof
:end
chooseFavorite returns the favorite in an environment variable. The output shows that reviewList continues looping after the favorite is identified.
Diet Favorites
skip apples
found the favorite - bananas
skip chocolates
Processing completed.
The comparison is working, but if the exit worked as expected, chocolates diet option should not be listed at all. How do I neatly break out of the loop iteration?
#ECHO Off
SETLOCAL
echo.
echo Diet Favorites
set "favorite=bananas"
for %%a in (apples, bananas, chocolates) do call :reviewList %%a&IF DEFINED foundFavorite GOTO foundit
:foundit
echo.
echo Processing completed.
goto end
:reviewList param
set "foundFavorite="
call :chooseFavorite "%~1"
if DEFINED foundFavorite (
echo found the favorite - %~1
) else (
echo skip %~1
)
goto :eof
:chooseFavorite param
if "%~1"=="%favorite%" set "foundFavorite=%~1"
goto :eof
:end
GOTO :EOF
Since you don't use any setlocal commands in your posted code, the endlocals are superfluous.
This version sets foundFavorite to empty, and sets it to something (can be anything you like - I just chose the thing that was found, which is often convenient) when a match is found. if defined variable interprets the run-time status of the variable, so it can be used within a for loop.
BTW- try running your original code with echo ON. You would see that your if statements are actually executing if /i ""false""=="true" ...
This is why it's convention on SO to use the set "var=value" syntax for string-assignments. You can then apply quotes as required without worrying about where or whether to apply or remove quotes that may be in variables.
Check the return code of :reviewList in your loop, and break accordingly. You'll need to call properly exit /b 0 on non-breaker calls, and exit /b 1 (or any non-zero value) for breaker calls.
Try that:
#echo off
echo.
echo Diet Favorites
set favorite="bananas"
for %%a in (apples, bananas, chocolates) do (
call :reviewList %%a || goto :break_loop
)
:break_loop
echo.
echo Processing completed.
goto end
:reviewList item
set foundFavorite="false"
call :chooseFavorite "%~1"
if /I "%foundFavorite%"=="true" (
echo found the favorite - %~1
exit /b 1
) else (
echo skip %~1
)
endlocal
exit /b 0
:chooseFavorite item
if "%~1"==%favorite% set "foundFavorite=true"
endlocal & goto :eof
:end
Output is:
S:\Temp>test
Diet Favorites
skip apples
found the favorite - bananas
Processing completed.
I was looking for a batch file, that saves one of listed files as variable, then proceeds to get some information about it and then set him as already listed, and then list every other file until there are none left. Important is to make %FILE% as single file (ex.: C:\folder\file.ext)
I was trying this:
#echo off
:loop
for %%x in (%dir%\*) do set FILE=%%x
if %FILE%=%alreadyusedfile% goto loop
goto scan
:scan
echo Now scanning %FILE%
(do some things here)
set alreadyusedfile=%alreadyusedfile% %FILE%
goto loop
But seems it doesn't work. Any ideas?
You need to process the files within the loop which you have two options.
Using the CALL command to make your code work like a function.
#echo off
for %%x in (%dir%\*) do call :scan "%%x"
goto :eof
:scan
echo Now scanning "%~1"
(do some things here)
Goto :eof
Or do everything within the FOR construct.
#echo off
for %%x in (%dir%\*) do (
echo Now scanning %%x
do some things here
)
Below is a batch script that I have put together which copies the content of another folder and pastes it into a new folder that it creates called IC_Transfer.
#echo off
#break off
#title IC Transfer
setlocal EnableDelayedExpansion
if not exist "C:\Temp\IC_Transfer" (
md "C:\Temp\IC_Transfer"
ROBOCOPY /-y "Q:\Work\Temp\Dan" "C:\Temp\IC_Transfer" /mir
if "!errorlevel!" EQU "0" (
echo Transfer Successful! )
) else (
if exist "C:\Temp\IC_Transfer" (
echo Error Transferring File
echo File Already Exists
:Choice
set /P c=Would You Like To Overwrite[Y/N]?
if /I "%c%" EQU "Y" goto Overwrite
if /I "%c%" EQU "N" goto Stop
) )
:Overwrite
md "C:\Temp\IC_Transfer"
ROBOCOPY "Q:\Work\Temp\Dan" "C:\Temp\IC_Transfer" /mir
if "!errorlevel!" EQU "0" (
echo Transfer Successful )
goto End
:Stop
echo Transfer Cancelled
goto End
:End
pause
exit
pause
exit
The make directory and robocopy functions work as they should by purging the directory, re-creates it and pastes the contents. What I cannot get working is the choice command.
Regardless of whether I choose Y or N it overwrites the file contents.
I'm new to batch scripts so any help would be appreciated
#echo off
#break off
#title IC Transfer
setlocal
if not exist "C:\Temp\IC_Transfer" (
md "C:\Temp\IC_Transfer"
ROBOCOPY /-y "Q:\Work\Temp\Dan" "C:\Temp\IC_Transfer" /mir
if not errorlevel 1 (
echo Transfer Successful!
) else (
echo Error Transferring File
echo File Already Exists
call :Choice
)
)
exit /b
:Choice
setlocal
set "c="
set /P "c=Would You Like To Overwrite[Y/N]? "
if /I "%c%" == "Y" (
call :Overwrite
) else if /I "%c%" == "N" (
call :Stop
) else call :Stop
exit /b
:Overwrite
ROBOCOPY "Q:\Work\Temp\Dan" "C:\Temp\IC_Transfer" /mir
if not errorlevel 1 echo Transfer Successful
pause
exit /b
:Stop
echo Transfer Cancelled
pause
exit /b
To fix the issue, labels inside parenthese code blocks is a
bad idea and prone to error. So call the label instead.
I replaced the goto's with calls as :Choice will work with a call.
This makes :End obsolete.
You used delayed expansion for errorlevel, though you could just use
i.e. if not errorlevel 1 to check if integer value is less than 1.
Delayed expansion has been removed.
Labels within code blocks (parenthesised series of commands) cause problems (:choice) and are better regarded as illegal.
You have invoked delayedexpansion and recognised that errorlevel may change with the code block. Your set /p changes the variable c, but you are using the parse-time value of c (%c%) in your if statements, not the run-time value (!c!)
What happens should the user enter not-YN? Hint: See the choice command - choice /? from the prompt.
Since c is not set at the start of the code, "%c%" will evaluate to "" which is neither "Y" nor "N" so the ifs fail and the code will then proceed to the next statement (:overwrite)
Note that md will create a directory or generate an error message if it does not exist, hence
md directoryname 2>nul
should create the directory and suppress error messages (like 'directory already exists') obviating the test-for-existence gating the md.
I have a batch file with 10 lines and 5 functions in a batch script. How can I ensure that all the commands in a batch file are successful.
In other way, what's the logic to calculate return code of each command at the end of a script.
1. #ECHO OFF
2. if not exist "%Destination%\%NAME%" md %Destination%\%NAME%
3. if not exist "%Destination%\%NAME2%" md %Destination%\%NAME2%
4. rmdir %Destination%\%NAME3%
5. if not exist "%Destination%\NAME4%" md %Destination%\%NAME4%
6. cd /d X:\test1
in the above 5 lines, 4th line returns %ERRORLEVEL% 1 and 6th line returns the same. But, I could not put IF %ERRORLEVEL%==0 after every command. So, how could i script to handle this.
You should firstly save your file as .cmd instead of .bat for better error handling. Also always enclose your paths with double quotes. Then I suggest you test existance as well to overcome errorlevel.
If exist "%Destination%\%NAME3%" rmdir "%Destination%\%NAME3%"
For the code example I suggest following:
#echo off
rem Verify the existence of all used environment variables.
for %%I in (Destination NAME NAME2 NAME3 NAME4) do (
if not defined %%I (
echo Error detected by %~f0:
echo/
echo Environment variable name %%I is not defined.
echo/
exit /B 4
)
)
rem Verify the existence of all used directories by creating them
rem independent on existing already or not and next verifying if
rem the directory really exists finally.
for %%I in ("%Destination%\%NAME%" "%Destination%\%NAME2%") do (
md %%I 2>nul
if not exist "%%~I\" (
echo Error detected by %~f0:
echo/
echo Directory %%I
echo does not exist and could not be created.
echo/
exit /B 3
)
)
rem Remove directories independent on their existence and verify
rem if the directories really do not exist anymore finally.
for %%I in ("%Destination%\%NAME3%") do (
rd /Q /S %%I 2>nul
if exist "%%~I\" (
echo Error detected by %~f0:
echo/
echo Directory %%I
echo still exists and could not be removed.
echo/
exit /B 2
)
)
cd /D X:\test1 2>nul
if /I not "%CD%" == "X:\test1" (
echo Error detected by %~f0:
echo/
echo Failed to set "X:\test1" as current directory.
echo/
exit /B 1
)
This batch file handles nearly all possible errors which could occur during execution of this batch file. A remaining problem could be caused by an environment variable containing one or more double quotes in its value. The solution would be using delayed expansion.
Linux shell script interpreters have the option -e to exit immediately execution of a script if any command or application returns with a value not equal 0. But Windows command interpreter cmd.exe does not have such an option. The options of cmd.exe can be read on running in a command prompt window cmd /?.
So it is necessary to use in a batch file:
if exist "..." exit /B 1 or goto :EOF
if not exist "..." exit /B 1 or goto :EOF
if errorlevel 1 exit /B 1 or goto :EOF
... || exit /B 1 or ... || goto :EOF
See also the Stack Overflow articles:
Windows batch files: .bat vs .cmd?
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
What are the ERRORLEVEL values set by internal cmd.exe commands?
Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?
I've spent a few days trying to get this batch script to work, but it just does not seem to work properly. It seems to just do whatever it wants after it prompts me to set a variable and i set it.
For example, I might enter n when it says that it doesn't seem to exist, and it will just end the script like it should. But if I re-open it, and it says the same thing as before, and I enter n again, it might just jump to :DeleteCalc, as if I typed y.
Here's my script:
#echo off
:Begin
color fc
title My script
cls
if not exist "C:\calc.exe" (
echo calc.exe doesn't seem to exist. Attempt deletion anyway? ^(Y/N^)
set "calcnotexist="
set /p "calcnotexist="
::This command checks to see if the user inputs a quotation mark. If they do, it echos that quotes cannot be inputted.
setlocal EnableDelayedExpansion
if not !calcnotexist!==!calcnotexist:^"=! set "calcnotexist="
endlocal & if "%calcnotexist%"=="" (
echo ERROR - Quotes cannot be entered.
pause
goto Begin
)
if /i "%calcnotexist%"=="Y" (
echo.
goto DeleteCalc
)
if /i "%calcnotexist%"=="Yes" (
echo.
goto DeleteCalc
)
if /i "%calcnotexist%"=="N" goto End
if /i "%calcnotexist%"=="No" goto End
echo ERROR - Unrecognized input
pause
goto Begin
)
:calcDoesExist
title My script
cls
echo calc.exe found. Delete? ^(Y/N^)
set "calcexist="
set /p "calcexist="
::This command checks to see if the user inputs a quotation mark. If they do, it echos that quotes cannot be inputted.
setlocal enabledelayedexpansion
if not !calcexist!==!calcexist:^"=! set "calcexist="
endlocal & if "%calcexist%"=="" (
echo ERROR - Quotes cannot be entered.
pause
goto calcDoesExist
)
if /i "%calcexist%"=="Y" goto DeleteCalc
if /i "%calcexist%"=="Yes" goto DeleteCalc
if /i "%calcexist%"=="N" goto End
if /i "%calcexist%"=="No" goto End
echo ERROR - Unrecognized input
pause
goto calcDoesExist
:DeleteCalc
cls
echo Deleting...
if not exist C:\calc.exe goto Success
del /f /q C:\calc.exe >nul 2>nul
if not exist C:\calc.exe goto Success
echo Fail!
echo.
echo calc.exe could not be deleted.
echo.
pause
goto End
:Success
echo Deleted!
echo.
echo calc.exe successfully deleted.
echo.
pause
goto End
:End
exit /b
What could I possibly be doing wrong?
Thanks
P.S. I tested this by opening CMD and running the batch script multiple times in there. (but it also doesn't work right when just double clicking it)
If you restructure your script there will be no need for the extended If blocks and therefore no necessity to EnableDelayedExpansion. Also if you use Choice you will not have to do all of the verification of responses.
Example:
#Echo Off
Title My script
Color FC
:Begin
If Exist "C:\calc.exe" GoTo calcDoesExist
Echo(calc.exe doesn't seem to exist.
Choice /M "Attempt deletion anyway"
If ErrorLevel 3 (ClS & GoTo Begin)
If ErrorLevel 2 GoTo End
If ErrorLevel 1 GoTo Success
GoTo End
:calcDoesExist
Echo(calc.exe found.
Choice /M "Delete"
If ErrorLevel 3 (ClS & GoTo calcDoesExist)
If ErrorLevel 2 GoTo End
If ErrorLevel 1 GoTo DeleteCalc
GoTo End
:DeleteCalc
ClS
Echo(Deleting...
Del /A /F "C:\calc.exe">Nul 2>&1
If Not Exist "C:\calc.exe" GoTo Success
Echo(Fail!
Echo(
Echo(calc.exe could not be deleted.
GoTo End
:Success
Echo(
Echo(Deleted!
Echo(
Echo(calc.exe does not exist.
:End
Echo(
Echo(Exiting...
Timeout 3 /NoBreak>Nul
Exit /B