2

This part works well until there is an ampersand in the filename, in which case it crashes my script completely.

echo %filename% | findstr /i /b /c:"%name% (%year%)"

I can't just put the filename into quotation marks because I need to find the string at the beginning. So how can I do both?

Bricktop
  • 533
  • 3
  • 22

2 Answers2

6

For command line use:

echo %file^name:^&=^^^&% | ...

Inside a batch file

echo %%filename:^&=^^^&%% | ...

How it works?
As a pipe creates two new cmd.exe instances, the echo ... will be parsed twice.
The trick is to expand the filename only in the second expansion.
And then to expand and replace the & with ^& to avoid problems with the &.
The caret will be used to escape the ampersand and itself will be removed.
In the second expansion the parser only sees echo %filename:&=^&%.

To force the expansion into the second parse step, the percent signs have to be doubled for batch files.
From the command line, this doesn't work, but a simple caret anywhere in the variable name works.

Alternative solution:

echo "%filename%" | findstr /i /b /c:^"\"%filename% (%year%)\""

This adds simply quotes and uses also quotes in the search expression

jeb
  • 78,592
  • 17
  • 171
  • 225
  • 1
    escaping, double escaping, forcing double-parsing, delayed expansion... sometimes I'm still surprised that work can indeed be done... – Stephan Jul 07 '17 at 06:21
  • thank you! ..my first steps on learning all the things stephan mentioned. – Bricktop Jul 07 '17 at 08:02
  • Alternative solution does NOT work for me on Win 10. Initial solution does. – Zimba Oct 28 '19 at 15:24
3

Another option is to use delayed expansion, which requires an explicit cmd with the /v:on option.

cmd /v:on /c "(echo !filename!)" | findstr /i /b /c:"%name% (%year%)"

If your batch script already has enabled delayed expansion, then parentheses around the left side are needed to prevent the delayed expansion from occurring within the parent script (see Why does delayed expansion fail when inside a piped block of code?). The child process will still default to disabled delayed expansion, so the cmd /v:on /c ... is still needed.

@echo off
setlocal enableDelayedExpansion
...
(cmd /v:on /c "(echo !filename!)") | findstr /i /b /c:"%name% (%year%)"

Another way to delay the expansion until the sub-process is to escape the expansion

@echo off
setlocal enableDelayedExpansion
...
cmd /v:on /c "(echo ^!filename^!)" | findstr /i /b /c:"%name% (%year%)"
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • You forgot the necessary, surrounding parenthesis `(cmd /v:on /c "(echo !filename!)") | ...`. Else `filename=%path%` fails – jeb Jul 08 '17 at 09:55
  • @jeb - I was assuming delayed expansion is not enabled in the batch script. But yes, if the batch has delayed expansion enabled, then the outer parentheses on the left side would be needed. – dbenham Jul 08 '17 at 13:09