1

In particular, I have problems understanding the hyphens in the following lines, which are from wikibooks

if not -%1-==-- echo Argument one provided
if -%1-==-- echo Argument one not provided & exit /b

To test if a variable exists or defined, there are basically two ways, which I learned from here:

IF DEFINED MyVar (ECHO MyVar IS defined) ELSE (ECHO MyVar is NOT defined)

IF "%MyVar%"=="" (ECHO MyVar is NOT defined) ELSE (ECHO MyVar IS defined)

So, what does (1) the hyphens around the %1 argument, and (2) the hyphens after the == sign mean?

11
  • 1
    one comment of yours mentioned %%, that's used in a for loop in a batch file like %%f not for the batch command line parameters %1 %2 %3. From the command line you can do for %1 in (*.*) do @echo %1 and it'd be ambiguous to do that in a batch file so for statements when within a batch file use %% but batch parameters (which btw are only ever in a batch file), are always %1,%2 etc
    – barlop
    Jul 31, 2015 at 12:16
  • Dear midnite: It's 2015. Why are you still using a programming language so poor as batch scripting? You could switch to VBScript, JScript, PowerShell, or one of many other choices. Jul 31, 2015 at 15:49
  • "However, these require the scripting language interpreter to be installed before they can be used" - no harm to learn more, esp it runs on most PCs natively ;-)
    – midnite
    Jul 31, 2015 at 15:57
  • 1
    @midnite I guess with batch, there's a limit to the number of problems you can run into..So I learnt over years by asking and fiddling.. And there seem to be geniuses that have figured out stuff that's not written in any references, when it gets really difficult. For example.. dave benham and jeb.. I think both post here, and also on dostips forum.. And as for a reference there is the original vfrazee.com/ms-dos/6.22/help that appeared in DOS when you ran HELP.COM (you can click e.g. IF then examples), and there is ss64.com/nt
    – barlop
    Jul 31, 2015 at 16:50
  • 1
    these little C programs can help show how programs break things into parameters to help with escapign quotes problems superuser.com/questions/944745/sed-command-with-apostrophe/… And if you ever went nuts deep, then jeb and dbenham have written posts about how the batch interpreter works.. found via testing it rather than any reference stackoverflow.com/questions/4094699/…
    – barlop
    Jul 31, 2015 at 16:56

3 Answers 3

6

Consider this

C:\>if not -%1-==-- echo Argument one provided
Argument one provided

C:\>if not P%1P==PP echo Argument one provided
Argument one provided

It should be evident that the minus/hyphen character is simply being used to facilitate the designation of an empty value. That specific symbol has no special meaning in that expression - it is treated like any other non-special character.

We can add spaces to make it clearer that the == operator is not being modified by surrounding characters

C:\>if not P%1P == PP echo Argument one provided
Argument one provided

Generally, it is better to use conventional approaches that more people will more immediately understand (e.g. use of quote marks).

C:\>if not "%1"=="" echo Argument one provided
Argument one provided

With DOS and perhaps early versions of Windows, I believe there were some problems (which I don't recall) with using quote marks which led to people using printable characters in this way. I haven't tried the case where %1 contains a quote mark for example.

5
  • I see. Thanks very much. So it essentially means concatenating two characters before and after the variable, isn't it? OTOH, I tried using the defined keyword to verify if the parameter exists. Both IF DEFINED %1 and IF DEFINED %%1 seem do not work. Would you give me some hints?
    – midnite
    Jul 31, 2015 at 10:47
  • You write " the minus/hyphen character is simply being used to simplify the designation of an empty value" <--- the word "simplify" is probably isn't a good one word to use 'cos it doesn't just simplify(whatever simplify would mean). But as you know, it prevents an error for when no argument is given.
    – barlop
    Aug 2, 2015 at 4:19
  • @barlop: Thanks for the comment. Answer edited. Aug 2, 2015 at 11:06
  • Good edit, but at the end you have written "With DOS and perhaps early versions of Windows, I believe there were some problems (which I don't recall) with using quote marks " <-- Still are. re using "%1" see my answer.. I initially said quotes were great around a %1, then supercat, commented, and I corrected it.
    – barlop
    Aug 2, 2015 at 12:26
  • You write "haven't tried the case where %1 contains a quote mark for example." <-- If the user provides them and you don't do "%1" then fine. If the user provides them and you add them with "%1" then not fine
    – barlop
    Aug 2, 2015 at 13:32
4

It's important when using %1 to put something around it to prevent the batch file from breaking when %1 is empty, because %1 isn't a variable it gets substituted with the value, like SQL injection an example of injection in batch, and when the value is nothing, and the %1 is in an IF, then you get broken code. if %1=="" becomes if == "" and gives an error.

As for why if defined doesn't work on %1, %1 is the value not the variable so hence defined doesn't work there. For code that works for %1 being empty you need code that won't break when %1 is substituted with nothing. Try if "%1"=="" or try if [%1]==[]

To say -%1 does look a bit confusing, it doesn't look like a good convention to me! Technically you could even do if a%1==a%1 or if %1a==%1a but convention tends to be []

You can use quotes, or [] or whatever character(s). But as supercat has pointed out in comment, quotes are not a good idea around a %1. (Because if the %1 contains spaces, the user include quotes in what gets passed to be %1, and if there is a space in the %1 and in the batch file you put quotes around the %1, the quotes will cancel out and the unquoted space there will cause an error ).

If you were doing an IF on the command line and not testing any variable, you'd have no %1 and you'd not even need []. You'd say IF "a b c"=="a b c" echo a or IF a==b echo a If in a batch file then you often have %1, and rather than use quotes around the %1, use e.g. one or two characters around it e.g. [%1] and use quotes if you need to preserve spaces and it's not a %1 e.g. e.g. IF [%1]==[a] or IF [%1]==["a b"] echo a Don't do "%1" because the %1 might already have quotes which your quotes will cancel out and then if the %1 has a space your if statement breaks.

If you were on the command line and were testing a variable then it depends whether the variable has quotes. You can look at the contents.

It is possible for a variable to have a space and not contain quotes.

So in this particular command line case, putting quotes around %a% will not double quotes, and you have to put quotes around the %a% if you want to test it against "a b"

C:\>set a=a b

C:\>echo %a%
a b

C:\>IF %a%=="a b" echo sdf
b=="a b" was unexpected at this time.

C:\>IF "%a%"=="a b" echo sdf
sdf

So ^^^ we want "%a%"

Whereas if %a% contained quotes, it'd be a different case

C:\>set a="a b"

C:\>echo %a%
"a b"

C:\>IF %a%=="a b" echo a
a

C:\>IF "%a%"=="a b" echo a
b""=="a b" was unexpected at this time.

C:\>

^^^^ So there we want %a% without quotes around it.

So it's all a question of whether the variable or parameter contains quotes. If the %1 has spaces in it then it will contain quotes. So we know that if we were comparing %1 to "a b" then w wouldn't do "%1". And if %1 didn't contain quotes it wouldn't contain spaces, so we wouldn't do "%1" So I think you'd never want to do "%1". So, if %1 contains spaces, there will be quotes within the %1 and the spaces will already be preserved.

I crossed out the below in light of supercat's comment. And I added more to my post above.

Quotes are best around the %1, rather than [] or some character like A or -, because for example, if you use [] then it won't preserve spaces

C:\>if [d a b]==[d a b] echo sdf

a was unexpected at this time.

Say if "d a b" that will work. So if "%1" is better than other character(s) like if [%1] or a%1a or -%1

9
  • 2
    The only way %1 will expand to something containing spaces will be if the argument contains quote marks. In that case, surrounding %1 with quote marks will yield broken behavior, and surrounding it with something else should work.
    – supercat
    Jul 31, 2015 at 17:24
  • 2
    What if the quoted argument contains spaces?
    – supercat
    Jul 31, 2015 at 18:05
  • 1
    @supercat ah I see, well spotted. if "" 2""==""2"" echo a fails. And in case anybody doesn't know.. The "" will have the effect of turning quoting on and off.
    – barlop
    Jul 31, 2015 at 18:08
  • 1
    @midnite it has some resemblance to the concatenation you see in more advanced languages, but I think functionally not so much 'cos with java etc, concatenation is of two separate entities even when you do "asdf"+"asdf". Whereas with cmd, "asdf""asdf" isn't joining two separate objects. The first " means turn on a mode where spaces and some other characters are preserved. The next " means turn that mode off. The next turns it on. So you can say "asdf asdf" or you can say asdf" "asdf So 2"" shouldn't look too tricky. (but sometimes figuring out how cmd/batch works is tricky)
    – barlop
    Aug 1, 2015 at 9:40
  • 1
    @midnite also I doubt that batch file(in general) distinguish strings and numbers, though some commands or functionality within command do. Whether 2 is a number or string is down to interpretation.. If you say echo 2 there's no conversion of 2 to a string. I suppose technically with computers it's all encoded (I won't say characters) squiggles/glyphs. Some may look at the presentation, if quotes or not, and then treat it accordingly, as a number(for calculation) or as a string(to sort them alphabetically). Or just as the encoded glyphs they are whether numbers or strings.
    – barlop
    Aug 1, 2015 at 10:00
1

Not sure you're quite getting it, so let me see if I can simplify it.

Let's say your batch file receives a value %1 on the command line, and you want to see if it is "cat" or "dog". You can test for that:

if %1 == cat goto CAT
if %1 == dog goto DOG
REM Default: Complain about no dog or cat
goto OOPS
:CAT
echo I'm a cat!
REM Successful, so skip to end
goto END
:DOG
echo I'm a dog!
goto END
:OOPS
echo I didn't see a cat or dog!
REM This just falls through to the end
:END

%1 is replaced with the text of cat or dog (let's say dog), so the interpreter actually sees this:

if dog == cat goto CAT
if dog == dog goto DOG

But if the person running the script didn't include a value on the command-line, the interpreter will see this:

if  == cat goto CAT
if  == dog goto DOG

That is incorrect syntax and will generate an error. So the convention is to include 1 or more characters and test for no variable first, something like this:

if %1* == * goto OOPS
REM If no value passed in, this is seen as  if * == *  which evaluates to true
if %1 == cat goto CAT
if %1 == dog goto DOG
goto END
:CAT
echo I'm a cat!
goto END
:DOG
echo I'm a dog!
goto END
:OOPS
echo You were supposed to include a type of pet!
:END

If %1 evaluates to nothing, the extra character(s) are still there to keep the syntax correct. I use *, but quotes or exclamations are also common, like "%1" or %1!, as well as hyphens, like --%1 or -%1-, etc..

Man, I can't believe I still remember all this. :-) I hope this helps!

2
  • You wrote "But if the person running the script didn't include a variable," <-- you might mean "a value" 'cos it's more a value than a variable. It's passing data, maybe one could say a value. And as for how it's passed, (in programming some more advanced languages, you can have 'pass by value' or 'pass by reference' I guess one would say this is passed by injection!
    – barlop
    Aug 1, 2015 at 13:40
  • "you might mean 'a value [rather than a variable]"... Oops! Right you are! Aug 3, 2015 at 16:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .