Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
914 views
in Technique[技术] by (71.8m points)

windows - Why does `findstr` with variable expansion in its search string return unexpected results when involved in a pipe?

While trying to provide a comprehensive answer to the question Why is FindStr returning not-found, I encountered strange behaviour of code that involves a pipe. This is some code based on the original question (to be executed in a ):

rem // Set variable `vData` to literally contain `...;%main%ProgramsGoBin`:
set "vData=...;%%main%%ProgramsGoBin"
set "main=C:Main"

echo/%vData%| findstr /I /C:"%%main%%\Programs\Go\Bin"

This does not return a match, hence nothing is echoed and ErrorLevel becomes set to 1.

Though when I go through the parsing process step by step, I conclude the opposite, I do expect a match and an ErrorLevel of 0, because:

  1. at first, the whole line is parsed and immediate (%) expansion takes place, hence %vData% becomes expanded and %% become replaced by %, resulting in the following command line that is going to be executed:

    echo/...;%main%ProgramsGoBin| findstr /I /C:"%main%\Programs\Go\Bin"
    
  2. each side of the pipe | is executed in its own new cmd instance by cmd /S /D c, both of which run in cmd context (which affects handling of %-expansion), resulting in these parts:

    • left side of the pipe:

      echo/...;C:MainProgramsGoBin
      
    • right side of the pipe:

      findstr /I /C:"C:Main\Programs\Go\Bin"
      

      (the search string that findstr finally uses is C:MainProgramsGoBin as the is used as escape character even in literal search mode, /C or /L)

As you can see the final search string actually occurs within the echoed string, therefore I expect a match, but the command lines does not return one. So what is going on here, what do I miss?


When I clear the variable main before executing the pipe command line, I get the expected result, which leads me to the conclusion that the variable main becomes not expanded despite my assumption above (note that in cmd context, %main% is kept literally when the variable is empty). Am I right?


It is getting even more confusing: when I put the right side of the pipe in between parentheses, a match is returned, independent on whether or not the variable main is defined:

echo/%vData%| (findstr /I /C:"%%main%%\Programs\Go\Bin")

Can anyone explain this? Could this be connected to the fact that findstr is an external command, opposed to echo? (I mean, break | echo/%vData% expands the value of main as expected if defined...)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I simplified your example to:

@echo off

set "main=abc"
break | findstr /c:"111" %%main%%
break | echo findstr /c:"222" %%main%%

The output is:

FINDSTR: %main% kann nicht ge?ffnet werden.
findstr /c:"222" abc

This proves that using an exe-file in a pipe results in different behaviour than using an internal batch command.
Only for internal commands a new cmd.exe instance will be created.
That's also the cause why the findstr doesn't expand the percent signs.

This confusing line expands, because the parentheses forces a new cmd.exe instance.

break | (findstr /c:"111" %%main%%)

I will modify the explanation at 5.3 Pipes - How does the Windows Command Interpreter (CMD.EXE) parse scripts?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...