My script isn't logging the contents of run.txt to log.txt
I've tried to remove the delete command to see if it was deleting it too quickly and therefore couldn't log. But that wasn't the case.
What should I change?
#ECHO OFF &setlocal
SET File=run.txt
type %File%
for /f "tokens=*" %%A in (%File%) do (echo >> log.txt)
del "%File%" /s /f /q > nul
pause
Here is a very simple way to do the task you are requiring.
#echo off
REM Will only grab the first line of the file
set /p file=<run.txt
REM For the last line use a for loop
for /f "tokens=*" %%a in (%file%) do set last_line=%%a
(
echo %file%
)>>log.txt
del /f %file% >nul
If not %errorlevel% equ 0 (
ECHO ERROR - %errorlevel%
pause
exit /b
)
ECHO Success!
timeout /t 003
exit /b %errorlevel%
EXPLANATION
set /p is for set prompt. For more information you can use set /? in your CMD window or check out this site.
I wish I could speak more on what < does, but what it is doing here is piping the content of run.txt to our variable.
Then we echo out our variable to our log file with (ECHO This is our %file%)>>destination
>> is to append where > is to overwrite the file.
(
echo %file%
echo.
)>>%file%
Checking for an error is probably unnecessary, but I believe it is a good habit to build on which is what I am trying to do with that If not %errorlevel% statement.
No error? We Success and timeout ourselves for xxx seconds.
Try:
#ECHO OFF &setlocal
SET "File=run.txt"
type "%File%" >> "log.txt" && (del "%File%" /f > nul)
pause
I have a batch script that is calling a VBscript file. It reiterates through all files in a watched folder.
It needs to verify if the file name has spaces in it and if so reject the file and not process it with the VBS.
I must have an error on the code as I get the error message:
ELSE was not expected at this time.
I have looked at the documentation and searched for the answer for quite some time, including this question: check "IF" condition inside FOR loop (batch/cmd)
But still, I can't see what is wrong in my syntax:
#ECHO OFF
setlocal ENABLEDELAYEDEXPANSION
call :ReadIni Infolder inFolder
call :ReadIni Outfolder outFolder
echo %inFolder%
echo %outFolder%
pause
:StartLoop
FOR %%I in (%inFolder%\*.srt) DO (
ECHO %%I
ECHO %%~nxI
SET TESTNAME=%%~nxI
ECHO !TESTNAME!
ECHO !TESTNAME: =_!
PAUSE
IF NOT !TESTNAME!==!TESTNAME: =_! (
move "%~sdp0%%~nxI" "%outFolder%\ERROR_IN_FILE_NAME_%%~nxI"
) ELSE (
copy /y "%%I" "%~sdp0%%~nxI"
%~sdp0SRToffset.vbs "%~sdp0%%~nxI" "%~sdp0%%~nxI"
IF %ERRORLEVEL%==1 (
Goto StartLoop
) else (
move "%~sdp0%%~nxI" "%outFolder%\"
move "%~sdp0QC_%%~nxI" "%outFolder%\"
del "%%I"
)
)
)
timeout /t 1
goto StartLoop
:ReadIni
FOR /F "tokens=2 delims==" %%a in ('find "%~1=" config.ini') do set %~2=%%a
exit /b
Any help would be appreciated.
IF NOT "!TESTNAME!"=="!TESTNAME: =_!" (
...
IF %ERRORLEVEL%==1 (
Quoting the strings causes cmd to regard the string as a single entity.
Note that the following if %errorlevel% will be executed using the value of errorlevel at :startloop. (See delayed expansion for reasoning.)
Cure by using if !errorlevel!==1 (. (Using the runtime value of errorlevel as established by the vbs routine.)
I need to forward the output of the copy command to WRITELOG function. is there anyway to do this? This is what I tired and not works
copy /y %source% %destination%>WRITELOG
:WRITELOG
if not "%1"=="" (
echo %time% : %*>>%LOGFILE%
)
The suggestion by Stephan would be coded for example as:
#echo off
setlocal EnableDelayedExpansion
set "source=%~1"
set "destination=%~2"
set "LOGFILE=%TEMP%\CopyLog.txt"
for /F "delims=" %%L in ('copy /Y "%source%" "%destination%" 2^>nul') do (
set "CopyOutput=%%L"
if not "!CopyOutput:copied=!" == "%%L" echo %time% : %*>>%LOGFILE%
)
endlocal
For an explanation on how the used commands work, open a command prompt window, run there following commands and read help output for each command:
copy /?
for /?
if /?
set /?
However, this solution is not good because of following reasons:
String copied in IF condition depends on language of command copy.
If the file(s) in source are found, but could not be copied to destination because destination is write-protected, the output of copy is 0 file(s) copied. which is interpreted by this code as successful copy.
The second disadvantage could be avoided by using:
#echo off
setlocal EnableDelayedExpansion
set "source=%~1"
set "destination=%~2"
set "LOGFILE=%TEMP%\CopyLog.txt"
for /F "tokens=1,3" %%A in ('copy /Y "%source%" "%destination%" 2^>nul') do (
echo %%A %%B
if not "%%A" == "0" (
if "%%B" == "copied." echo %time% : %*>>%LOGFILE%
)
)
endlocal
But much better would be evaluating exit code of command copy which is 0 on success and greater 0 on error.
#echo off
setlocal
set "source=%~1"
set "destination=%~2"
set "LOGFILE=%TEMP%\CopyLog.txt"
copy /Y "%source%" "%destination%" >nul 2>nul
if not errorlevel 1 echo %time% : %*>>%LOGFILE%
endlocal
See the Microsoft support article Testing for a Specific Error Level in Batch Files.
if not errorlevel 1 means if exit code of previous command is NOT greater or equal 1 then ...
Or in other words if exit code of previous command is smaller than 1 then ...
Command copy never exits with a negative value like all internal commands of cmd.exe and nearly all console applications because 0 is standard for success and a value greater 0 is an indication for an error.
The batch has to remove files and directories from specific locations and output success or stdout/stderr messages to a new .txt file. I have created the most of the script and it performs exactly as it should, except when the deletion is successful it moves forward to the next line rather than echo a 'successful' message on the log.
echo Basic Deletion Batch Script > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 0 echo succesful
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
For some reason I can't find the syntax for if del succeeds echo 'successful'. In the above example if I remove the line
if errorlevel 0 echo successful
Everything works fine, but no success message. With this line left in it echoes success for every line.
del and ErrorLevel?
The del command does not set the ErrorLevel as long as the given arguments are valid, it even resets the ErrorLevel to 0 in such cases (at least for Windows 7).
del modifies the ErrorLevel only in case an invalid switch is provided (del /X sets ErrorLevel to 1), no arguments are specified at all (del sets ErrorLevel to 1 too), or an incorrect file path is given (del : sets ErrorLevel to 123), at least for Windows 7.
Possible Work-Around
A possible work-around is to capture the STDERR output of del, because in case of deletion errors, the related messages (Could Not Find [...], Access is denied., The process cannot access the file because it is being used by another process.) are written there. Such might look like:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
To use the code in command prompt directly rather than in a batch file, write %# instead of %%#.
If you do not want to delete read-only files, remove /F from the del command line;
if you do want prompts (in case wildcards ? and/or * are present in the file path), remove /Q.
Explanation of Code
This executes the command line del /F /Q "\path\to\the\file_s.txt". By the part 2>&1 1> nul, the command output at STDOUT will be dismissed, and its STDERR output will be redirected so that for /F receives it.
If the deletion was successful, del does not generate a STDERR output, hence the for /F loop does not iterate, because there is nothing to parse. Notice that ErrorLevel will not be reset in that case, its value remains unchanged.
If for /F recieves any STDERR output from the del command line, the command in the loop body is executed, which is set =; this is an invalid syntax, therefore set sets the ErrorLevel to 1. The 2> nul portion avoids the message The syntax of the command is incorrect. to be displayed.
To set the ErrorLevel explicitly you could also use cmd /C exit /B 1. Perhaps this line is more legible. For sure it is more flexible because you can state any (signed 32-bit) number, including 0 to clear it (omitting the number clears it as well). It might be a bit worse in terms of performance though.
Application Example
The following batch file demonstrates how the above described work-around could be applied:
:DELETE
echo Deleting "%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F "tokens=*" %%# in ('del /F /Q "C:\Users\newuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted "%~1" succesfully.
goto :EOF
Presetting ErrorLevel
Besides the above mentioned command cmd /C exit /B, you can also use > nul ver to reset the ErrorLevel. This can be combined with the for /F loop work-around like this:
> nul ver & for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Alternative Method Without for /F
Instead of using for /F to capture the STDERR output of del, the find command could also be used like find /V "", which returns an ErrorLevel of 1 if an empty string comes in and 0 otherwise:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
However, this would return an ErrorLevel of 1 in case the deletion has been successful and 0 if not. To reverse that behaviour, an if/else clause could be appended like this:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)
Different Approach: Checking File for Existence After del
A completely different approach is to check the file for existence after having tried to delete it (thanks to user Sasha for the hint!), like this, for example:
del /F /Q "\path\to\the\file_s.txt" 1> nul 2>&1
if exist "\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)
When using this syntax, instead of this
if errorlevel 0 echo successful
you can use this - because errorlevel 0 is always true.
if not errorlevel 1 echo successful
Just use rm from UnxUtils (or gow or cygwin). It sets the errorlevel correctly in case of a nonexistent file, or any errors deleting the file.
This was added as an edit by the original asker, I have converted it to a community wiki answer because it should be an answer, not an edit.
I found out how to do it... one way anyway.
echo Startup > results.txt
#echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1 >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1
dir c:\users\newuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1 echo "successful" )
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
IF ERRORLEVEL 0 [cmd] will execute every time because IF ERRORLEVEL # checks to see if the value of ERRORLEVEL is greater than or equal to #. Therefore, every error code will cause execution of [cmd].
A great reference for this is: http://www.robvanderwoude.com/errorlevel.php
>IF /?
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
I would recommend modifying your code to something like the following:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 1 (
rem This block executes if ERRORLEVEL is a non-zero
echo failed
) else (
echo succesful
)
GOTO :EOF
If you need something that processes more than one ERRORLEVEL, you could do something like this:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done
GOTO :EOF
OR
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER
:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done
GOTO :EOF
The answer of aschipfl is great (thanks, helped me a lot!) using the code under Presetting ErrorLevel you get a nice standard function:
Take care to use %~1 instead of %1 in the del statement, or you will get errors if you use a quoted filename.
::######################################################################
::call :DELETE "file.txt"
::call :DELETE "file.txt" "error message"
:DELETE
>nul ver && for /F "tokens=*" %%# in ('del /F /Q "%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
if NOT .%2==. echo %~2
)
goto :EOF
BTW 1: You can give a nifty error message as a second parameter
BTW 2: Using :: instead of REM for comments makes the code even more readable.
Code:
Error Code: (What you did)
if errorlevel 0 echo succesful
The problem here is that you aren't calling errorlevel as a variable and plus you didn't add in the operator to the statement as well.
Correct Code: (Here is what it should actually be.)
if %ERRORLEVEL% EQU 0 echo succesful
Definitions:
EQU: The EQU stands for Equal. This kind of operator is also called a relational operator. Here is the documentation link to operators if you wanna know more, there are other ones but this helped me.
ERRORLEVEL: is declared as a variable and usually get the error level of the last command run usually. Variables are usually called when they are between percent signs like this
%foo%
For some more help on variables, go to cmd (Which you can go to by searching it on windows 10) and type in "set /?", without the quotes. the set command is the command you use to set variables
#echo off
setlocal enabledelayedexpansion
>result.txt (
for /f %%a in (srvrname.txt) do (
ping -n 1 %%a > nul && echo %%a up||echo %%a DOWN
))
I was doing a ping test for some servers with the above script. I want to understand how the output of the ping command is passed to echo UP or echo DOWN section..As in unix we have $? to know if the previous command executed successfully like if[$? -eq 0] then; do success else failure done.
How does this happen in a batch script. DO WE HAVE A VARIABLE like $? in batch. Please let me know. Also please suggest if we could make the pingtest script any better.
I think you are looking for %errorlevel%.
This will give you the error code for the last command that executed.
if %errorlevel%==0 echo SUCCESS
if %errorlevel%==1 echo FAIL
Note: There is a whole range of errorcodes that could be set, I just used 1 as an example, check the command documentation to find the errorcode's meaning.
Beware though, if you are using %errorlevel% in your for loop you will need to use delayed expansion.
You already have it added on your script (setlocal enabledelayedexpansion), so you just need to change the %'s to !'s.
#echo off
setlocal enabledelayedexpansion
>result.txt (
for /f %%a in (srvrname.txt) do (
ping -n 1 %%a > nul
if !errorlevel!==0 (
echo Ping replied successfully
) else (
echo There was an error
)
))