I have a problem with a nested loop and usage of errorlevel. I want to delete files on multiple computers with batch files. For this I have a batch file that iterates through the computers and calls another batch files that deletes the files. On some computers I want to delete the files in a second folder.
The first part of the code works as expected, but the second part with the nested loop doesn't work. the code is:
SETLOCAL enabledelayedexpansion
REM %1 is a parameter from the calling batch file
FOR %%A IN (M:\Folder\) DO del /Q "%%A" 2>&1 1> NUL | find /V "" 1> NUL 2>&1 & IF ERRORLEVEL 1 (1> NUL ver) ELSE (2> NUL SET =)
IF !ERRORLEVEL! == 1 (
ECHO !ERRORLEVEL!
) ELSE (
ECHO OK
)
FOR %%N IN (%computers%) do (
IF %%N EQU %1 (
FOR %%A IN (M:\Folder2\) DO del /Q "%%A" 2>&1 1> NUL | find /V "" 1> NUL 2>&1 & IF ERRORLEVEL 1 (1> NUL ver) ELSE (2> NUL SET =)
IF !ERRORLEVEL! == 1 (
ECHO !ERRORLEVEL!
) ELSE (
ECHO OK
)
)
)
Related
I have a simple batch-file which starts first veracrypt and after mounting another batch-file:
C:
cd C:\Program2\VeraCrypt
veracrypt /v \Device\Harddisk2\Partition1 /l L /a /p 123xyz /q
cd /D D:\backup
start_backup.bat
start_backup.bat starts a backup using robocopy (Windows 10) which updates/copies files from one drive C to an external encrypted harddrive D respectively L (mount name).
If veracrypt can't mount the drive for any reason (e.g. there is no drive) the batch start_backup.bat will be started without backup since encrypted drive is not accessible. How can I avoid the start of start_backup.bat in case the drive couldn't be mounted?
The batch-file is written with commands of cmd.exe.
Simple way to do this is using operator: && and || ...
#echo off && setlocal EnableDelayedExpansion
cd /d "C:\Program2\VeraCrypt"
(
.\veracrypt.exe /v \Device\Harddisk2\Partition1 /l L /a /p 123xyz /q
) && (
cd /D "D:\backup" & call start_backup.bat
) || (
echo/ something really wrong is going on here....
%__APPDIR__%timeout.exe -1
goto :EOF
)
rem :: continue with more task here.... or goto :EOF
Or...
#echo off && setlocal EnableDelayedExpansion
cd /d "C:\Program2\VeraCrypt"
.\veracrypt.exe /v \Device\Harddisk2\Partition1 /l L /a /p 123xyz /q && (
cd /D "D:\backup" & call start_backup.bat ) || (
echo/ Something really wrong is going on here....
%__APPDIR__%timeout.exe -1 & goto :EOF )
rem :: continue with more task here.... or goto :EOF
Option to go through three attempts and with a timeout of 30 seconds
#echo off && setlocal EnableDelayedExpansion
cd /d "C:\Program2\VeraCrypt"
:loop
set /a "_cnt+=1+0"
(
.\veracrypt.exe /v \Device\Harddisk2\Partition1 /l L /a /p 123xyz /q
) && (
cd /D "D:\backup" & call start_backup.bat
) || (
echo/ something really wrong is going on here....
if "!_cnt!"=="3" (
echo/ Some is really wrong here....
%__APPDIR__%timeout.exe -1 & goto :EOF
) else (
echo/ Let's try +1 times until 3 [!_cnt!/10]
%__APPDIR__%timeout.exe 30
goto :loop
)
)
Option to go through three attempts and with a timeout of 30 seconds by using if !errorlevel! 0/1 else as suggested by #Stephan...
#echo off && setlocal EnableDelayedExpansion
cd /d "C:\Program2\VeraCrypt"
:loop
set /a "_cnt+=1+0" && type nul>nul
.\veracrypt.exe /v \Device\Harddisk2\Partition1 /l L /a /p 123xyz /q
if !errorlevel! == 0 (
cd /D "D:\backup" & call start_backup.bat
) else (
echo/ Something really wrong is going on here....
if "!_cnt!"=="4" (
echo/ Some is really wrong here....
%__APPDIR__%timeout.exe -1 & goto :EOF
) else (
echo/ Let's try +1 times until 03 [0!_cnt!/03]
%__APPDIR__%timeout.exe 30
goto :loop
)
)
Where does goto eof return to
Operator/Syntax Redirection in bat/cmd
I have a batch file which moves .tiff/tif files from one folder to another if the filename has digits, for example,
0000002341567.tif. It is working fine but
my requirement is to move file even if it has a name like 000000234156-7 or 0000002341567-s
So to say the file name can be suffixed with - and a one digit number or a hyphen and a character.
for %%I in ("C:\Documents\Pictures\*.tif*") do (
if !FileCount! EQU 0 (
echo Exiting after having moved already %FileCount% TIF files.
goto LoopEnd
)
set "HasOnlyDigits=1"
for /F "tokens=1 delims=0123456789" %%T in ("%%~nI") do set "HasOnlyDigits=%%T"
if "!HasOnlyDigits!" == "1" (
move /Y "%%I" "%FolderGood%"
)
findstr has a very limited set of REGEX, but it is enough for this task:
#echo off
set filecount=1
setlocal enabledelayedexpansion
for %%I in ("*.tif*") do (
if !FileCount! EQU 0 (
echo Exiting after having moved already %FileCount% TIF files.
goto LoopEnd
)
echo %%~nI|findstr /R "^[0-9][0-9]*-.$" >nul && (
echo yes %%I
ECHO move /Y "%%I" "%FolderGood%"
set filecount+=1
) || (
echo no %%I
)
)
:loopend
The REGEX here consists of:
^ Start of the line (string)
[0-9] Any digit
[0-9]* any digit (zero or any nunmber of any digit) (previous [0-9] to ensure, there is minimum one digit)
- a dash
. any character
$ End of the line (string)
REM ---### FTP_Batch ###---
#echo off
REM Get first line record and store in %%A
setlocal enableDelayedExpansion
for /F "tokens=*" %%A in (FTP_Account_with_Password_and_EOL.txt) do (
REM Run WinSCP with %%A as open connection
"C:\Program Files (x86)\WinSCP\WinSCP.com" ^
/log="c:\temp\WinSCP.log" /loglevel=1 /ini=nul ^
/command ^
"%%A" ^
"ls" ^
"exit"
%WINSCP_RESULT% = %ERRORLEVEL%
if %ERRORLEVEL% neq 0 (
echo Error
echo %ERRORLEVEL% %%A
) else (
echo Success %ERRORLEVEL% %%A
echo Winscp Result %WINSCP_RESULT%
)
pause
)
ENDLOCAL
exit /b %WINSCP_RESULT%
I have this script within a .bat file and would like to only keep the most recent 100 lines, at the end of the file.
How do I delete all other rows?
#echo off
REM *DATETIME2.BAT
REM *Copy date and time to create a new log file
echo.|date>>"\\spserver\myfolder\dt.tmp"
echo.|time>>"\\spserver\myfolder\dt.tmp"
IF NOT EXIST "\\spserver\myfolder\dt.tmp" GOTO Error1
type "\\spserver\myfolder\dt.tmp"|FIND "current">"\\spserver\myfolder\dt.log"
rem del "\\spserver\myfolder\dt.tmp"
GOTO End
:Error1
Echo.
Echo There was an error processing the command.
Echo Unable to find temporary sort file DATETIME2.TMP.
Echo.
GOTO End
:End
Here you go:
Call :Tail 100 dt.log tempout.txt
move /y tempout.txt dt.log>nul
exit /b
:Tail <numlines> <FileIn> <FileOut>
FOR /F "usebackq tokens=3,3 delims= " %%l IN (
`find /c /v "" %2`) DO (call SET find_lc=%%l)
SET /a linenumber=%find_lc%-%1
IF %linenumber% LSS 1 (
more +0 %2 >> %3
) ELSE (
more +%linenumber% %2 >> %3
)
We check error using
if !ERRORLEVEL! NEQ 0 (do something)
but this is littered everywhere in the batch file.
1) Is the a way to encapsulate it to log and exit program upon error?
2) how do I log the bat file line number that is causing the error?
#ECHO OFF
SETLOCAL
ECHO y|FIND "y" >NUL
CALL aberr matching y and y
pause
ECHO x|FIND "y" >NUL
CALL aberr matching x and y
pause
ECHO y|FIND "z" >NUL
CALL aberr matching y and z
pause
GOTO :EOF
The above is a testing scenario, setting errorlevel to 0, 1, 1 in succession, then CALLing then batch aberr.bat to analyse the result.
Here's aberr.bat
#ECHO OFF
IF %ERRORLEVEL%==0 GOTO :EOF
ECHO %ERRORLEVEL% found %*
EXIT
Note here that there is no SETLOCAL (which would set ERRORLEVEL to zero) and that the routine EXITs.
Consequence is that if aberr.bat is on the PATH then the message produced would show the errorlevel found plus any text that was on the CALL aberr line after CALL aberr.
You could place a PAUSE after the ECHO %ERRORLEVEL% line to show the result, or log the result to a file by using
>>logfile.txt ECHO %ERRORLEVEL% found %*
at 1) How to log and exit the batch Exit from nested batch file
at 2) How to get the current line number?
Mix them and you get it.
setlocal EnableDelayedExpansion
cd. & REM *** Set the errorlevel to 0
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
set /a n=0xGH 2> nul & REM Force the errorlevel to !=1
if %errorlevel% NEQ 0 (
call :getLineNumber errLine uniqueID4711 -2
call :log ERROR: in line !errLine!
)
echo all OK
exit /b
:log
>error.log echo %*
call :HALT
exit /b
:HALT
call :__halt 2> nul
exit /b
:__halt
()
:::::::::::::::::::::::::::::::::::::::::::::
:GetLineNumber <resultVar> <uniqueID> [LineOffset]
:: Detects the line number of the caller, the uniqueID have to be unique in the batch file
:: The lineno is return in the variable <resultVar> add with the [LineOffset]
SETLOCAL
for /F " usebackq tokens=1 delims=:" %%L IN (`findstr /N "%~2" "%~f0"`) DO set /a lineNr=%~3 + %%L
(
ENDLOCAL
set "%~1=%LineNr%"
goto :eof
)
Use something like:
...
if !ERRORLEVEL! NEQ 0 Call :LogAndExit "some explanation"
...
GoTo :EOF
:LogAndExit
Echo %Date% %Time% - %~1>>Log.txt
Exit /B