Cmd and exclamation marks - Part II

与世无争的帅哥 提交于 2019-11-29 11:54:00

That's because you enable delayed expansion after set "line=%%a":

set "line=%%a"
@echo on & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set "line=!line:.wav=%NewExtension%!"

If you enable delayed expansion before assigning %%a:

@echo on & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set "line=%%a"
set "line=!line:.wav=%NewExtension%!"

you'll get

Special | < > ~ \ ²³ { [ ] } € $ % & / ( ) = ? chars.flac

instead of

Special | < > ~ \ ²³ { [ ] } ! " ´ ' ` üäö @ ; : € $ % & / ( ) = ? chars.flac


Edit: Delayed expansion controls when variables in a statement are expanded. The critical statement in your script is the line

set "line=%%a"

which assigns the value of the loop variable %%a to the variable line. With delayed expansion disabled the literal value of %%a is assigned, because the script interpreter cannot expand %%a at parse time. However, when you enable delayed expansion, bang-variables are expanded at execution time, so the interpreter looks at the value of %%a and expands any !whatever! in it before the result is assigned to the variable line.

Perhaps it'll become clearer with an example. If you add a line

%foo% !foo!

to the input file and define the variable in the script:

@echo on & setlocal ENABLEEXTENSIONS

set "foo=bar"
set "InFile=%~1"
...

When you enable delayed expansion after set "line=%%a" neither %foo% nor !foo! are expanded before %%a is assigned to the variable line (the interpreter doesn't see the value of %%a before execution time), so you get this output:

%foo% !foo!

When you enable delayed expansion before set "line=%%a" the interpreter will expand bang-variables before assigning the result to the variable line, so you get this output:

%foo% bar

%foo% would only be expanded at parse time, at which point the interpreter cannot see the actual value of %%a, so %foo% remains a literal %foo% here.

Further assignments like set "line=!line:.wav=%NewExtension%!" don't affect bangs or percent signs inside a variable, because expansion isn't transitive, i.e. it translates !line! to %foo% bar (or %foo% !foo!) and then stops.

You can force the expansion of (percent-)variables inside variables with the call command, though. A command call set "line=!line!" first expands to call set "line=%foo% bar" in the current context, and then call evaluates set "line=%foo% bar" in a new context where %foo% is expanded to bar as well, so the variable line is assigned the value bar bar.


Just as a side note: your code is way too complicated. You'd get the exact same results with this:

set "FileToParse=%~1"
set "OutputFile=%~2"
set "NewExtension=%~3"
for /F "usebackq tokens=* delims=" %%a in ("%FileToParse%") DO (
  set "line=%%a"
  @setlocal ENABLEDELAYEDEXPANSION
  set "line=!line:.wav=%NewExtension%!"
  echo(!line!>>"%OutputFile%"
  endlocal
)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!