ScienceDiscoverer
ScienceDiscoverer

Reputation: 202

Why some varaiables need %% and others don't in Windows batch files?

For example, this:

ffmpeg -i %1 -c:v libx264 -preset medium -crf 30 -c:a aac "%~n1_OUT.mp4"

Does not need %%1 and %%~n1 respectively.

But this:

FOR /f %%f in ('dir /b .') DO somecommand %%f

Needs %%, otherwise it's not working.

Can somebody explain any logical reason for this chaotic design?

Upvotes: 1

Views: 194

Answers (2)

aschipfl
aschipfl

Reputation: 34949

The percent-sign % is used by cmd.exe and also its predecessor command.com to mark expansion1 of environment variables (like %VAR%), for-loop meta-variables (like %I/%%I), and argument references in batch files (like %1).

There are two distinct parsing modes, which behave differently when it comes to %-expansion:

  • Command line mode:
    • There are no command line arguments, hence no argument references are supported.
    • Empty (undefined) variables are not expanded, meaning that %VAR% is kept as is when an environment variable VAR is not set.
    • There is no escaping of %-signs supported, so %%VAR%% results in % + value of VAR + %.
  • Batch file mode:
    • Batch files may have arguments, which are expanded by argument references like %1.
    • Empty (undefined) variables are expanded to a blank string.
    • Escaping of the %-sign is supported in that %% represents a literal %.

Of course I cannot tell why the developers decided the parser to behave that way, but I believe there are several factors contributing:

  • The command line mode existed before batch file mode, the latter of which required introduction of support for arguments, which in turn led to the demand to let the parser distinguish between variable or argument references.
  • When the for command was introduced2, the developers decided to use the %-sign too to mark loop meta-variables, leading to conflicts in command line mode, particularly because empty variables remain: For instance, an expression like %foo%bar results in the value of foo + bar when variable foo is set, but otherwise to value of %f + oo + value of %b + ar when loop variables %f and %b exist, and so on. This is particularly because for parses the command line a second time after the initial potential expansion of environment variables.
  • Introduction of batch file mode and the conflicts coming from the for parser probably led to the decision of improved handling of %-expansion in that undefined variables are treated differently by expanding such to empty strings. In order to still be able to yield literal %-symbols, escaping like %% was introduced: For example, a text like 10% plus 20% could not be returned without escaping since a variable named SPACE + plus 20 is most likely undefined; however, specifying 10%% plus 20%% results in the literal string 10% plus 20%.

Anyway, the %-escaping in batch file mode is the intrinsic reason for why for meta-variables need to be specified like %%I (in contrast to %I in command line mode) in order for them to survive the escaping, resulting in %I, which is then recognised by the for command parser that comes into play after %-expansion.

For detailed information about what exactly happens, refer to: How does the Windows Command Interpreter (CMD.EXE) parse scripts?


1) The term expansion means to replace an expression (like %VAR%) by the string value it refers to (like the one stored in the respective environment variable named VAR) while parsing.
2) Although I do not know whether the for command was introduced before or after implementation of the batch file mode.

Upvotes: 2

user2956477
user2956477

Reputation: 1360

Command started from console window use single percent sign in for loop varible, but script files uses doubled percent sign. Its by design, well documented. Nothing chaotic..

https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/for

Upvotes: 0

Related Questions