Win10 Batch script: \Notepad++ was unexpected at this time - windows

This batch file gives the error in the title:
if "%PROCESSOR_ARCHITECTURE%"=="x86" (
echo FOOBAR
) else (
set HOME_EDIT=%SystemDrive%\Program Files (x86)\Notepad++
)
This is on a Win10 Pro x64 system (so the test is false).
Strangely the "set HOME_EDIT..." line, if executed by itself, does NOT generate the error. And this batch file seemed to work OK a few weeks ago (oldest complaint in the book, I know, but maybe the recent Win10 Creator's Update chagned something?).
Here's the whole output:
U:\Users\Dave\data\PC setup\2017-03 PC Setup for Win10>test.bat
\Notepad++ was unexpected at this time.
U:\Users\Dave\data\PC setup\2017-03 PC Setup for Win10> set HOME_EDIT=C:\Program Files (x86)\Notepad++
U:\Users\Dave\data\PC setup\2017-03 PC Setup for Win10>

Putting quotes around the assignment certainly solves the problem, but it has nothing to do with spaces. The problem is the ) in the path is closing the ELSE block prematurely unless the path is quoted (or escaped).
Without quotes, the ELSE block becomes
) else (
set HOME_EDIT=%SystemDrive%\Program Files (x86
)
And then the \Notepad++ is indeed unexpected, causing a syntax error.
I see 3 ways to eliminate the syntax error:
1) Eliminate the parentheses and put the SET command on the same line as ELSE
else set HOME_EDIT=%SystemDrive%\Program Files (x86)\Notepad++
2) Put quotes around the assignment
) else (
set "HOME_EDIT=%SystemDrive%\Program Files (x86)\Notepad++"
)
3) Escape the closing parenthesis
) else (
set HOME_EDIT=%SystemDrive%\Program Files (x86^)\Notepad++
)
If I were to do the assignment, I would use the predefined environment variable for the folder.
) else (
set "HOME_EDIT=%ProgramFiles(x86)%\Notepad++"
)

Answering my own question:
#drescherjm was correct (in the comments) that the immediate problem was lack of quote marks ("foo") around the argument to SET. Somehow this matters when the SET is within a IF statement, even tho it doesn't otherwise.
But adding quotes just broke something else later in my batch script:
set NEW_PATH=%HOME_WINDOWS%
set NEW_PATH=%NEW_PATH%;%BinPath%
set NEW_PATH=%NEW_PATH%;%BinPath%\ffmpeg\bin
set NEW_PATH=%NEW_PATH%;%BinPath%\mplayer
set NEW_PATH=%NEW_PATH%;%BinPath%\gui
set NEW_PATH=%NEW_PATH%;%BinPath%\dll
set NEW_PATH=%NEW_PATH%;%HOME_CYGWIN%\bin
set NEW_PATH=%NEW_PATH%;%HOME_CYGWIN%\sbin
set NEW_PATH=%NEW_PATH%;%HOME_CYGWIN%\usr\bin
set NEW_PATH=%NEW_PATH%;%HOME_CYGWIN%\usr\sbin
set NEW_PATH=%NEW_PATH%;%HOME_7ZIP%
set NEW_PATH=%NEW_PATH%;%HOME_EDIT%
set NEW_PATH=%NEW_PATH%;%HOME_DIFF%
set Path=%NEW_PATH%
setx Path "%NEW_PATH%"
If HOME_EDIT has quote marks in it, this causes SETX to fail.
Here's the fix I came up with (note lines marked with "TRICK1"):
REM The following is a trick to get around spaces in the path (TRICK1)
set HOME_EDIT=%SystemDrive%\%ProgramFiles(x86)%\Notepad++
if "%PROCESSOR_ARCHITECTURE%"=="x86" (
set HOME_CYGWIN=%SystemDrive%\cygwin
set HOME_EDIT=%SystemDrive%\Program Files\Notepad++
) else (
set HOME_CYGWIN=%SystemDrive%\cygwin64
REM (TRICK1 rem this out) set HOME_EDIT=%SystemDrive%\%ProgramFiles(x86)%\Notepad++
)
The path with the spaces in it is SET as a default value prior to entering the IF statement. This way no quote marks are needed, and SETX doesn't break later.

Related

How to see if an environment variable is defined through batch script?

I am writing a batch script to use an existing environment variable if it exists. If it doesn't, I need to create that environment variable. When the env variable name exists already, the below code runs fine. When the env variable doesn't exist, it just pops up as a flash.
set "my_path=%ENV_VARIABLE_NAME%"
IF %my_path%=="" (
echo no path found
set "my_path = C:/Users/xyz/"
) ELSE (
echo path found
)
pause
Your main problem is the line
IF %my_path%=="" (
When the variable is empty, this is parsed as
IF =="" (
which is incorrect syntax. The parser shows an error message and ends parsing (closing your window when you started it with a double-click).
The proper syntax would be (quoting both sides of the comparison):
IF "%my_path%" == ""
Although I'd prefer #jeb's solution: IF defined my_path (
There is another issue in your code:
set "my_path = C:/Users/xyz/"
sets a variable %my_path % to <space>C:/Users/xyz/ - not what you want. Correct would be:
set "my_path=C:\Users\xyz\"
(Note: the correct path delimiter in Windows is a backslash, not a slash)
The syntax is:
IF defined my_path
See also the help IF /?
This is the mechanism I'd use to perform the task you've provided in your code.
#If Not Defined ENV_VARIABLE_NAME (
Echo No path found.
Set "my_path=C:\Users\xyz"
) Else (
Echo Path found.
Set "my_path=%ENV_VARIABLE_NAME%"
)
Or as a single line without the unnecessary echoing:
#If Not Defined ENV_VARIABLE_NAME (Set "my_path=C:\Users\xyz") Else Set "my_path=%ENV_VARIABLE_NAME%"
Alternatively:
#If Defined ENV_VARIABLE_NAME (
Echo Path found.
Set "my_path=%ENV_VARIABLE_NAME%"
) Else (
Echo No path found.
Set "my_path=C:\Users\xyz"
)
Or as a single line without the unnecessary echoing:
#If Defined ENV_VARIABLE_NAME (Set "my_path=%ENV_VARIABLE_NAME%") Else Set "my_path=C:\Users\xyz"
Of some small note, using IF Defined is not just a different way to check the variable, it is generally a preferable method as it provides two enhanced features:
As it It does not explcitly check the contents of the variable, but instead looks up the name when the command is run.
This means that if the contents of the variable were such that they would have been troublesome to correctly escape it provides no issue..
This also means that the command can be used inside for loops or parenthesis whether or not you use delayed expansion because it's lookup is strictly a command, and so must be done at execution instead of pre-execution
You can also replicate this functionality by using SET | FIND "MYVar=" as again this requires the set command to be run and check the state of the environment at execution, instead of pre-execution.

Why empty variables cause crash

Using empty variables doesn't necessarily cause a crash. But when using them inside an IF case will crash the program. Why? Even if EnableDelayedExpansion is not set here, why isn't e.g. the variable PATHDEF below not treated as an empty variable?
Calling the below script with input APP will cause a crash with different error messages. (I.e I call the script below with an input argument which will lead to IF evaluating to true)
On windows console: \Intel\iCLS was unexpected at this time.
On Bamboo server: \Graphviz2.38\bin was unexpected at this time.
echo off
SET app=%1
SET PATHDEF=%PATH%
echo %PATHDEF% <--- This works. Prints path
echo %THIS% <--- This works. Prints "ECHO is off" (since %THIS% is empty)
IF %app%==APP (
echo %PATHDEF% <--- This causes crash!
)
This is happening because of the unescaped close parenthesis in %PATH%. The first item in your PATH variable is C:\Program Files (x86)\Intel\iCLS Client\.
Variables are expanded at runtime, so
IF %app%==APP (
echo %PATHDEF%
)
is actually being read as
IF %app%==APP (
echo C:\Program Files (x86)\Intel\iCLS Client\;C:\WINDOWS\system32;C:\WINDOWS;
)
Because of how the cmd interpreter parses parentheses, it decides that the first unquoted, unescaped close parentheses is the end of the code block, so your code is being treated like you wrote
IF %app%==APP (
echo C:\Program Files (x86
)
\Intel\iCLS Client\;C:\WINDOWS\system32;C:\WINDOWS;
And since things outside of code blocks get processed first, the script recognizes that \Intel\iCLS is not a valid command, so it throws an error there instead of echoing C:\Program Files (x86.
There are two ways to avoid this:
OPTION ONE - Put the variable in quotes
IF %app%==APP (
echo "%PATHDEF%"
)
Unfortunately, this means the quotes get included when being displayed.
OPTION TWO - Put everything on the same line
IF %app%==APP echo %PATHDEF%
With no opening parenthesis to mess everything up, the contents will print correctly without the need to quote or escape anything.

") was unexpected at this time", Create list of files in a variable - Batch

So I am trying to create a batch file, that gets all the files in deletesrc and find's if it's name matches any folder in deletedest. To accomplish this, I have tried to generate a list of file names in deletesrc which is stored in deletefiles (in the format "first" "second" "third file"). Then I intend to loop through each folder in deletedest and check for it's existence in deletesrc (using this). So far I have managed:
setlocal enabledelayedexpansion
set "deletesrc=F:\Delete Source"
set "deletedest=C:\Users\Spaced Name\Delete\Dest"
set "deletefiles=" ::I think this is useless, but I would prefer it to be here
for /R "%deletesrc%\" %%i in (*) do (
set "deletefiles=!deletefiles!^"%%i^" "
::random comment that is source of error
)
set deletefiles=!deletefiles!:rTrim
echo !deletefiles!
The main problem is, I keep getting ) was unexpected at this time.
Placing an echo test as the first thing within the loop, does not change the output, implying the loop is not run and the error encountered first. Placing an echo just before the loop, does produce output and the error immediately after it.
If there are any syntax standards or things I should/should not be doing that do not answer the question, I would like to know.
Your problem is you're using :: as a comment inside your FOR loop. You can't do this because :: is actually the label designator and it is breaking the FOR loop.
Change this line:
::random comment that is source of error
To this:
REM random comment that is source of error
UPDATE
As foxidrive stated in the comments, you can use :: as a comment inside a FOR as long as it is not the last line before the closing ).
Try this:
set deletefiles=!deletefiles! "%%i"

Scripting in Windows Batch

I have a pretty simple batch file that is basically checking to see if an enviornment variable is set, and then attempting to set it. Its not setting the variable correctly, and I am pretty new to batch files in general so I had some general questions about the script I am writing. Any insight would be appreciated. Here are the questions I have.
In line 15, what if I dont know the full name of the directory? i.e. what if I just knew 'whistle' was a part of it, and wanted to check if it was == to DIR?
In lines 16 and 19, I am trying to say if I am in 'whistle-1.0.0', I know that the BELFRAMEWORK_HOME variable should be set to 1 directory above it. I try to do this with '%DIR%..\' but this seems to have no effect. How can I set BELFRAMEWORK_HOME to 1 directory above 'whistle-1.0.0'?
In lines 17 and 20, the BELFRAMEWORK_HOME variable is not printed. I do not understand why, because it is of the same form as lines 10 and 12, which echo the variable as expected. Why doesnt BELFRAMEWORK_HOME echo?
Last thing, are there any good online resources for learning more about this type of scripting?
Thanks!
1#echo off
2
3if not defined JAVA_OPTS (
4 set JAVA_OPTS=-Xmx1024m -Dderby.stream.error.field=org.openbel.framework.common.enums.DatabaseType.NULL_OUTPUT_STREAM
5) else (
6 set JAVA_OPTS=%JAVA_OPTS% -Dderby.stream.error.field=org.openbel.framework.common.enums.DatabaseType.NULL_OUTPUT_STREAM
7)
8
9set DIR=%CD%
10echo "DIR/CD : %DIR%"
11set DIR=%~dp0
12echo "DIR/~dp0 : %DIR%"
13
14if not defined BELFRAMEWORK_HOME (
15 if "%DIR%"=="whistle-1.0.0" (
16 set BELFRAMEWORK_HOME=%DIR%\..\
17 echo "DIR == whistle, BELFRAMEWORK_HOME is now: %BELFRAMEWORK_HOME%"
18 ) else (
19 set BELFRAMEWORK_HOME=%DIR%\..\
20 echo "DIR != whistle, BELFRAMEWORK_HOME is now: %BELFRAMEWORK_HOME%"
21 )
22)
23
24set WHISTLE_HOME=%~dp0
25java %JAVA_OPTS% -jar %WHISTLE_HOME%\whistle-1.0.0.jar %*
Oooh, 4 questions for the price of one :-)
1) I believe you want something like C:\folder\xxxxWHISTLExxxx\ to match, but not something like C:\xxxxWHISTLExxxx\folder\. If that is the case then you will want to use FINDSTR with a regular expression to make sure the last directory is what matches WHISTLE. The search must be case insensitive.
You don't want the FINDSTR output. You just want to know if the string is found. It returns 1 if not found (error) and 0 if found (success).
echo %DIR% | findstr /irc:"whistle[^\\]*[\\]*$" >nul && (
rem Code for success (string found)
)
rem Code for failure (string not found)
)
2) If you want the trailing backslash, then you can use
for %%A in ("%DIR%\.") do set "BELFRAMEWORK_HOME=%%~dpA"
If you don't want the trailing backslash, then use
for %%A in ("%DIR%\..") do set "BELFRAMEWORK_HOME=%%~fA"
3) You are experiencing a classic stumbling block for new batch users. The %BELFRAMEWORK_HOME% is expanded when the line is parsed, and the entire IF statement, including the parenthesized code blocks, is parsed as one statement. So the expanded value is the value that existed before the IF statement is executed.
You can solve the problem by using delayed expansion.
#echo off
setlocal enableDelayedExpansion
set var=BEFORE
(
set var=AFTER
echo within block normal expansion = %var%
echo within block delayed expansion = !var!
)
echo after block normal expansion = %var%
The result of the above is
within block normal expansion = BEFORE
within block delayed expansion = AFTER
after block normal expansion = AFTER
4) Here are my favorite batch scripting web sites
http://dostips.com
http://judago.webs.com
http://robvanderwoude.com/batchfiles.php
http://ss64.com/nt/syntax.html or http://ss64.com/nt/

Check for null variable in Windows batch

I'm working on a Windows batch file that will bcp three text files into SQL Server. If something goes wrong in production, I want to be able to override the file names. So I'm thinking of doing something like this.
bcp.exe MyDB..MyTable1 in %1 -SMyServer -T -c -m0
bcp.exe MyDB..MyTable2 in %2 -SMyServer -T -c -m0
bcp.exe MyDB..MyTable3 in %3 -SMyServer -T -c -m0
I would like to be able to enter default names for all three files, to be used if the positional parameters are not supplied. The idea would be either to execute
myjob.bat
with no parameters, and have it use the defaults, or execute
myjob.bat "c:\myfile1" "c:\myfile2" "c:\myfile3"
and have it use those files. I haven't been able to figure out how to tell if %1, %2 and %3 exist and/or are null. I also don't know how to set those values conditionally. Is this possible? Any suggestions would be appreciated.
To test for the existence of a command line paramater, use empty brackets:
IF [%1]==[] echo Value Missing
or
IF [%1] EQU [] echo Value Missing
The SS64 page on IF will help you here. Under "Does %1 exist?".
You can't set a positional parameter, so what you should do is do something like
SET MYVAR=%1
You can then re-set MYVAR based on its contents.
The right thing would be to use a "if defined" statement, which is used to test for the existence of a variable. For example:
IF DEFINED somevariable echo Value exists
In this particular case, the negative form should be used:
IF NOT DEFINED somevariable echo Value missing
PS: the variable name should be used without "%" caracters.
Both answers given are correct, but I do mine a little different. You might want to consider a couple things...
Start the batch with:
SetLocal
and end it with
EndLocal
This will keep all your 'SETs" to be only valid during the current session, and will not leave vars left around named like "FileName1" or any other variables you set during the run, that could interfere with the next run of the batch file. So, you can do something like:
IF "%1"=="" SET FileName1=c:\file1.txt
The other trick is if you only provide 1, or 2 parameters, use the SHIFT command to move them, so the one you are looking for is ALWAYS at %1...
For example, process the first parameter, shift them, and then do it again. This way, you are not hard-coding %1, %2, %3, etc...
The Windows batch processor is much more powerful than people give it credit for.. I've done some crazy stuff with it, including calculating yesterday's date, even across month and year boundaries including Leap Year, and localization, etc.
If you really want to get creative, you can call functions in the batch processor... But that's really for a different discussion... :)
Oh, and don't name your batch files .bat either.. They are .cmd's now.. heh..
Hope this helps.
rem set defaults:
set filename1="c:\file1.txt"
set filename2="c:\file2.txt"
set filename3="c:\file3.txt"
rem set parameters:
IF NOT "a%1"=="a" (set filename1="%1")
IF NOT "a%2"=="a" (set filename2="%2")
IF NOT "a%3"=="a" (set filename1="%3")
echo %filename1%, %filename2%, %filename3%
Be careful with quotation characters though, you may or may not need them in your variables.
Late answer, but currently the accepted one is at least suboptimal.
Using quotes is ALWAYS better than using any other characters to enclose %1.
Because when %1 contains spaces or special characters like &, the IF [%1] == simply stops with a syntax error.
But for the case that %1 contains quotes, like in myBatch.bat "my file.txt", a simple IF "%1" == "" would fail.
But as you can't know if quotes are used or not, there is the syntax %~1, this removes enclosing quotes when necessary.
Therefore, the code should look like
set "file1=%~1"
IF "%~1"=="" set "file1=default file"
type "%file1%" --- always enclose your variables in quotes
If you have to handle stranger and nastier arguments like myBatch.bat "This & will "^&crash
Then take a look at SO:How to receive even the strangest command line parameters?

Resources