Bat file and labels - cmd

I am trying to write a bat file for a network policy that will install a program if it doesn't exist as well as several other functions. I am using GOTO statements depending on whether or not certain criterion are met. However, it seems that the labels are not firing correctly as all of them do.
I have simplified my script so as to grasp some idea of what may be happening.
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
:MISSING
echo file missing
ping localhost -n 5 >NUL
Basically it checks to see that the file "test.txt" exists in folder "c:\test" which id does. So it should echo file exists to the console. However, both "file exists" and "file missing" are echoed to the console. I find that if I remove the file from the folder or simply rename it, it only echoes "file missing"
Why is it running running both labels?

Because a GOTO is just a jump in execution to a point in the script, then execution continues sequentially from that point. If you want it to stop after running 'EXISTING', then you need to do something like this. Note the extra GOTO and new label:
#ECHO OFF
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
goto :NEXTBIT
:MISSING
echo file missing
:NEXTBIT
ping localhost -n 5 >NUL
It's worth noting though that with cmd.exe (i.e., the NT-based command shells [NT, Win2k, XP, etc]), you can do IF...ELSE blocks like this:
#ECHO OFF
IF EXIST c:\test\test.txt (
ECHO File exists
) ELSE (
ECHO File missing
)
ping localhost -n 5 >nul
...so you can eliminate your GOTOs entirely.

It's because you need to skip over the "missing" bit if it exists:
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO :MISSING
:EXISTING
echo file exists
goto :COMMON
:MISSING
echo file missing
:COMMON
ping localhost -n 5 >NUL
You may also want to keep in mind that the current cmd.exe batch language is a fair bit more powerful than that which came with MS-DOS. I would prefer this one:
#echo off
if exist c:\test\test.txt (
echo file exists
) else (
echo file missing
)
ping localhost -n 5 >nul

After you echo file exists the next command is
echo file missing
You need to do something to skip the missing case. Perhaps another goto to a :PING label?
When you're debugging it helps to keep the echo on.

Because GOTO statement moves the execution to that label. To use it in the situation like yours, you need to add another GOTO label.
#echo off
IF EXIST c:\test\test.txt (GOTO :EXISTING) ELSE GOTO MISSING
:EXISTING
echo file exists
GOTO END
:MISSING
echo file missing
GOTO END
:END
ping localhost -n 5 >NUL

#echo off
IF EXIST "c:\test\test.txt" ( :: warning double quotes
GOTO EXISTING
) ELSE ( :: this format best in batch
GOTO MISSING
) :: don't forget
:EXISTING
echo file exists
goto OTHER :: if file exist jump OTHER
:MISSING
echo file missing
:: label is not required
:OTHER
timeout /t 5 >nul
pause

Related

Window batch commands to detect if downloaded file exists?

I use a windows batch file that scans download folder and if it detects label.pdf it sends to local printer. This works fine most of the time but often it detects file before the file completely downloads which causes PDFtoPrinter error. Is there a way to make sure the download process is complete before attempting to detect?
#echo off
cls
:start
IF EXIST "C:\Users\Downloads\label.pdf" (
echo "Found!"
ping 127.0.0.1 -n 1 -w 3000> nul
"C:\Users\Downloads\PDFtoPrinter" label.pdf "4BARCODE 4B-2054A"
ping 127.0.0.1 -n 1 -w 10000> nul
del "C:\Users\Downloads\label.pdf"
) ELSE (
echo "it isn't here!"
)
goto start
You can use the mechanism to check if a file is locked for exclusive access by another application.
#echo off
cls
:start
IF EXIST "C:\Users\Downloads\label.pdf" (
REM check if file is locked
2>nul (>>"C:\Users\Downloads\label.pdf" (call )) && ("C:\Users\Downloads\PDFtoPrinter" label.pdf "4BARCODE 4B-2054A") || (echo file is locked)
) ELSE (
echo "it isn't here!"
)
Timeout /T 10
goto start

find string in text file and then renaming my log file

im working on a basic .bat file.
It checks if various files exists and if they dont, it will write "ERROR" in the log file.
I then test this log file for the string "ERROR" and if it does I want to rename my log file, but i seem to be getting an error on my if statement. Heres my code..
set "filename=C:\Temp\%COMPUTERNAME%.txt"
echo Creating .txt file...
echo Getting the Computer name...
echo %COMPUTERNAME% >> filename
echo ArcGIS Desktop 10 File checker
pause
echo Looking for files.....
call:checkFileExists C:\support\msi_local\Oracle10g\marker.txt
pause
FIND "ERROR" filename
echo error level is %ERRORLEVEL%
pause
if %ERRORLEVEL% 1 (
set "newfileName=C:\Temp\%COMPUTERNAME%%_ERROR.txt"
rename fileName newfileName
)
pause
:checkFileExists
if exist %~1 (
echo Success %~1 does exist >> C:\Temp\%COMPUTERNAME%.txt
) else (
echo ERROR "C:\support\msi_local\Oracle10g\marker.txt"%~1 does not exist >> C:\Temp\%COMPUTERNAME%.txt
)
I get a error -
The syntax of teh command is incorrect.
C:\Windows>if ERRORLEVEL 1(
Where am i going wrong?
Thanks
try this:
#echo off &SETLOCAL
set "filename=C:\Temp\%COMPUTERNAME%.txt"
echo Creating .txt file...
echo Getting the Computer name...
>>"%filename%" echo %COMPUTERNAME%
echo ArcGIS Desktop 10 File checker
pause
echo Looking for files.....
call:checkFileExists "C:\support\msi_local\Oracle10g\marker.txt"
pause
FIND "ERROR" "%filename%"
echo error level is %ERRORLEVEL%
pause
if %ERRORLEVEL% equ 1 (
set "newfileName=C:\Temp\%COMPUTERNAME%_ERROR.txt"
move "%fileName%" "%newfileName%"
)
pause
:checkFileExists
if exist "%~1" (
echo Success %~1 does exist >> C:\Temp\%COMPUTERNAME%.txt
) else (
echo ERROR "C:\support\msi_local\Oracle10g\marker.txt"%~1 does not exist >> C:\Temp\%COMPUTERNAME%.txt
)
if %ERRORLEVEL% 1 (
should be
if ERRORLEVEL 1 (
And, since you're retyping the error rather than copy-pasting, note that there must be a space between the 1 and the (
The error appears that way because batch replaces any %var% with its value at that time (when it is 'parsed') and then executes the line, so batch substitutes whatever has been reported as %errorlevel% from your debug statement :) (eg 1) and then tries valiantly to work out what if 1 1 ( means.
(btw, it would be a good idea to replace if exist %~1 ( with if exist "%~1" (
This may seem redundant, removing and then replacing the quotes, BUT if you later decide to change the statement to if exist %file% ( it's only later you'll find out you'll get a crash when %file% contains a space. Best to be ever-mindful of the spaces-in-filenames problem; if you make quoting a habit, you'll be caught out less often.
)
The two syntaxes are subtly different:
Old style syntax (MS-DOS era) - check if the error level was 1 or more:
IF ERRORLEVEL 1
New style syntax - check if the %errorlevel% variable was not equal to 0:
IF %errorlevel% NEQ 0
Note that the new style syntax uses % to indicate a variable, while with the old style syntax, ERRORLEVEL is a special keyword.
The new style syntax should be preferred, because it will handle programs that return -1 on error. If the program can return negative error codes on success, you could handle errors with IF %errorlevel GEQ 1. Either way, using the %errorlevel% variable allows a lot more flexibility.
For clarity I've used upper case for keywords and lower case for variables, but it should be case sensitive either way.

Batch file add/remove hosts file entries syntax error

The following script is supposed to manage adding and removing entries into the hosts file. Entries with .dev are supposed to point to localhost and all others should prompt for an IP address. If the entry already exists it should ask you if you want to remove it.
I am getting a vague The syntax of the command is incorrect error but I'm not sure which line it's referring to. If I turn #echo on it then spits out if ( on the next line and then dies. The only way I can catch the error is to do a screenshot because it immediately exits.
I've spent several hours on this, so any assistance would be greatly appreciated!
#echo off
title ClearSight Studio
echo Virtual website setup script
echo Version 1.4
echo Last modified 12/30/2011
echo.
REM Get the name of the domain name
echo What domain name? Ctrl+C to cancel. Example: newdomain.dev.
set /p domain= Domain:
REM Set a variable for the Windows hosts file location
set hostpath=\windows\system32\drivers\etc
set hostfile=hosts
set sitespath=\clearsight\sites
set extension=%domain:~-3%
REM Make the hosts file writable
attrib -r %hostpath%\%hostfile%
REM Add the domain to point to localhost at the end of the file if it doesn't already have an entry.
find /c " %domain%" %hostpath%\%hostfile%
if errorlevel 1 (
if /i %extension%==dev (
set /p ip= What is the IP?
)
echo. >> %hostpath%\%hostfile%
echo.# Adding %domain% via batch process on %date:~10,4%-%date:~4,2%-%date:~7,2%. >> %hostpath%\%hostfile%
if %ip% (
echo.%ip% %domain% >> %hostpath%\%hostfile%
) else (
echo.127.0.0.1 %domain% >> %hostpath%\%hostfile%
)
) else if errorlevel 0 (
echo Entry found in hostfile already. Would you like to remove it?
set /p remove= Remove (Y/N)
if /i %remove%==Y (
findstr /v "%domain%" %hostpath%\%hostfile% > %hostpath%\%hostfile%
)
)
if /i %extension%==dev (
REM Create the folder if it doesn't exist
if exist %sitespath%\%domain% (
echo %sitespath%\%domain% already exists.
) else (
echo Creating %sitespath%\%domain%...
mkdir %sitespath%\%domain%
)
)
REM Clean up
attrib +r %hostpath%\%hostfile%
echo.
echo Done.
if /i %extension%==dev (
REM Do a "git" of the repo, if requested
echo Would you like to clone an external git repository named %domain% from Bitbucket?
echo This assumes the git repository was set up under the "jamonholmgren" account.
echo Do it manually if it's under someone else's account. Also, make sure you have permissions to this repo.
set /p getgit= Get git clone? (Y/N):
)
REM
if /i %getgit%==Y (
git clone git#bitbucket.org:jamonholmgren/%domain%.git %sitespath%\%domain%\
pause
) else (
echo Okay, then we're done.
pause
)
You have two problems with this bit of code
if %ip% (
echo.%ip% %domain% >> %hostpath%\%hostfile%
) else (
It is invalid syntax. I presume you want to test if the variable is defined. The proper syntax is if defined ip (
You are attempting to expand %ip% in the same if() block where it was defined. This can't work because %ip% is expanded at parse time, which is before you assign the value! The solution is to use delayed expansion instead !ip!. Delayed expansion must first be enabled, probably near the top of your script, using setlocal enableDelayedExpansion
So the fixed code would look something like this
setlocal enableDelayedExpansion
.
.
.
if defined ip (
echo.!ip! %domain% >> %hostpath%\%hostfile%
) else (
You have the same delayed expansion issue with %remove%
Edit - expanding on Andriy M's comment
You also have a potential issue with how you deal with user input for ip and remove. Both values should be initialized either to nothing, or to a default value, prior to prompting for the value. If the user does not enter anything, then the existing default value (if any) is preserved.
Also, you may want to confirm that a valid value was entered, especially for the ip. If you do, then you will want to take the prompt out of the loop and put it in a called subroutine. The subroutine can check if a value was entered and loop back to try again if it wasn't. It must be in a subroutine because you cannot GOTO within a parenthesized block of code like you have with your IF statement.
When you expand a variable value via %variable% its value is expanded just once after the line that contain commands is read and before the commands are executed. For example:
set var=Original
set var=New & echo %var%
Previous line show "Original". The same effect happen with any command enclosed in parentheses (that belong to any IF or FOR commands).
The way to solve this problem is using Delayed Variable Expansion by enclosing a variable in exclamation marks instead percents:
set var=Original
set var=New & echo !var!
However, you must first activate the delayed expansion with this command:
setlocal EnableDelayedExpansion
So, insert previous line at beginning of your program and change ALL references to variables that may change its value inside an IF or FOR by !name! instead of %name%. For example:
if %ip% (
that I'm sure is the line that caused your problem...
Thanks everyone for the help! Here is the final (working) result in case anyone ever wants to do something similar. The output to the screen could probably use a little tweaking but in all my testing it seems completely reliable.
#echo off
setlocal enableDelayedExpansion
title ClearSight Studio
echo Virtual website setup script
echo Version 1.5
echo Last modified 2/23/2012
echo.
REM Get the name of the domain name
echo What domain name? Ctrl+C to cancel. Example: newdomain.dev.
set /p domain= Domain:
REM Set a variable for the Windows hosts file location
set hostpath=\windows\system32\drivers\etc
set hostfile=hosts
set sitespath=\clearsight\sites
set extension=%domain:~-3%
REM Make the hosts file writable
attrib -r %hostpath%\%hostfile%
REM Add the domain to point to localhost at the end of the file if it doesn't already have an entry.
find /c " %domain%" %hostpath%\%hostfile%
if errorlevel 1 (
if /i NOT %extension%==dev (
set /p ip= What is the IP?
) else (
set ip=127.0.0.1
)
echo. >> %hostpath%\%hostfile%
echo.# Adding %domain% via batch process on %date:~10,4%-%date:~4,2%-%date:~7,2%. >> %hostpath%\%hostfile%
echo.!ip! %domain% >> %hostpath%\%hostfile%
) else if errorlevel 0 (
echo Entry found in hostfile already.
set /p remove= Would you like to remove it? (Y/N)
if /i !remove!==Y (
findstr /v %domain% %hostpath%\%hostfile% > %hostpath%\%hostfile%.txt
type %hostpath%\%hostfile%.txt > %hostpath%\%hostfile%
)
)
if /i %extension%==dev (
REM Create the folder if it doesn't exist
if exist %sitespath%\%domain% (
echo %sitespath%\%domain% already exists.
) else (
echo Creating %sitespath%\%domain%...
mkdir %sitespath%\%domain%
)
)
REM Clean up
attrib +r %hostpath%\%hostfile%
REM Flush DNS so the changes are available imidiately
ipconfig /flushdns
echo.
echo Done.
if /i %extension%==dev (
REM Do a "git" of the repo, if requested
echo Would you like to clone an external git repository named %domain% from Bitbucket?
echo This assumes the git repository was set up under the "jamonholmgren" account.
echo Do it manually if it's under someone else's account. Also, make sure you have permissions to this repo.
set /p getgit= Get git clone? (Y/N)
)
REM
if /i !getgit!==Y (
git clone git#bitbucket.org:jamonholmgren/%domain%.git %sitespath%\%domain%\
pause
) else (
echo Okay, then we're done.
pause
)
Just some hints for debugging the batch file:
Start it from a cmd shell to avoid closing the window after exiting
Add more REM commands that will serve as log entries when turning echo on
Simplify your script by repeatedly removing parts from the end until it runs without error. Reinsert the faulty parts and try to figure out what's wrong there
While this does not quite answer your question, I hope the hints will help you solve the problem. You are always welcome to ask for general advice, but I'm afraid that your particular problem is somehow a bit too specific to be of general interest.

Batch file help (Loops and Menus)

I currently have this menu:
echo What would you like to do?
echo.
echo Choice
echo.
echo 1 Delete File
echo 2 Ignore File
echo.
:choice
set /P C=[1,2]?
if "%C%"=="2" goto Deleting
if "%C%"=="1" goto IgnoreFile
goto choice
Although it does not seem to work, when I select an option e.g. 2 it will not goto the :IgnoreFile section, instead it will continue the script (i.e. continue with the next command in the file, after entering my choice)
Very thrustrating, I am not sur
If I understand correctly your problem, you should make a end mark to skip a sequence of your script.
#echo off
echo What would you like to do?
echo.
echo Choice
echo.
echo 1 Delete File
echo 2 Ignore File
echo.
:choice
set /P C=[1,2]?
if "%C%"=="1" goto Deleting
if "%C%"=="2" goto IgnoreFile
goto choice
:Deleting
echo Deleting
[your code]
goto end
:IgnoreFile
echo IgnoreFile
[your code]
goto end
:end
the "goto end" at the end of each case allow you to skip the reste of the script. Don't forget to make a ":end" part at the very last line of your script.
If you don't use "goto end" and selected the "Deleting" case, the deleting part would be executed and the script would keep on going and run the "IgnoreFile" case

Check for existence of all files before building a project

How would one go best about checking for existence of all files before building?
Let me explain; I mostly build stuff from the command prompt. No problems there, just put the build command and all in one .bat /.cmd file, and run it. It works fine.
But, for the normal running of my program, for example, I need several source files for the build, and then an additional few data files, measured data and such.
Is there a way to test via a batch file whether a file exists, and if it exists just write OK?
file1.for OK
file2.for OK
datafile.txt OK
data.dat MISSING FROM DIRECTORY
How could this be accomplished?
As a slightly more advanced approach:
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
Set FileList=file1.for file2.for "File with spaces" ...
Set Build=1
For %%f In (%FileList%) Do Call :FileExists %%f
If Not Defined Build (
Echo.
Echo Build aborted. Files were missing.
GoTo :EOF
)
...
GoTo :EOF
:FileExists
Set FileName=%~1
If Exist "!FileName!" (
Echo !FileName! OK
) Else (
Echo !FileName! MISSING FROM DIRECTORY
Set Build=
)
GoTo :EOF
You can put all files into the FileList variable. The Build variable controls whether to continue with the build. A single missing file causes it to cancel.
Something like this?
#ECHO OFF
IF EXIST "c:\myfile1.txt" (ECHO myfile1.txt OK) ELSE (ECHO myfile1.txt FILE MISSING FROM DIRECTORY)
IF EXIST "c:\myfile2.txt" (ECHO myfile2.txt OK) ELSE (ECHO myfile2.txt FILE MISSING FROM DIRECTORY)
For a list of available commands, see http://ss64.com/nt/

Resources