Why does delayed expansion fail when inside a piped block of code?

前端 未结 3 1149
粉色の甜心
粉色の甜心 2020-11-22 07:23

Here is a simple batch file that demonstrates how delayed expansion fails if it is within a block that is being piped. (The failure is toward the end of the script) Can anyo

3条回答
  •  暗喜
    暗喜 (楼主)
    2020-11-22 07:41

    Funny thing! I don't know the answer, what I know is that the pipeline operation have consistent failures in Windows Batch that should not be present in original MS-DOS Batch (if such features could be executed in old MS-DOS Batch), so I suspect that the error was introduced when the new Windows Batch features were developed.

    Here are some examples:

    echo Value to be assigned | set /p var=

    Previous line does NOT assign the value to the variable, so we must fix it this way:

    echo Value to be assigned > temp.txt & set /p var=< temp.txt

    Another one:

    (
    echo Value one
    echo Value two
    echo Value three
    ) | call :BatchSubroutine
    

    Doesn't work. Fix it this way:

    (
    echo Value one
    echo Value two
    echo Value three
    ) > temp.txt
    call :BatchSubroutine < temp.txt
    

    However, this method DO work in certain cases; with DEBUG.COM for example:

    echo set tab=9> def_tab.bat
    (
    echo e108
    echo 9
    echo w
    echo q
    ) | debug def_tab.bat
    call def_tab
    echo ONE%tab%TWO
    

    Previous program show:

    ONE     TWO

    In which cases works and which not? Only God (and Microsoft) may know, but it seems to be related to new Windows Batch features: SET /P command, delayed expansion, code block in parentheses, etc.

    EDIT: Asynchronous Batch files

    NOTE: I modified this section to correct an error of mine. See my last comment to jeb for details.

    As jeb said, the execution of both sides of a pipeline create two asynchronous processes, that made possible to execute asynchronous threads even if START command is not used.

    Mainfile.bat:

    @echo off
    echo Main start. Enter lines, type end to exit
    First | Second
    echo Main end
    

    First.bat:

    @echo off
    echo First start
    
    :loop
        set /P first=
        echo First read: %first%
    if /I not "%first%" == "end" goto loop
    echo EOF
    
    echo First end
    

    Second.bat:

    @echo off
    echo Second start
    
    :loop
        set /P second=Enter line: 
        echo Second read: %second%
        echo/
    if not "%second%" == "EOF" goto loop
    
    echo Second end
    

    We may use this capability to develop a program equivalent to Expect application (working in a similar way of pexpect Phyton module) that could control any interactive program this way:

    Input | anyprogram | Output
    

    Output.bat file will achieve the "Expect" part by analysing the output from the program, and Input.bat will achieve the "Sendline" part by providing the input to the program. The backwards communication from Output to Input modules will be achieved via a file with the desired information and a simple semaphore system controlled via the presence/absence of one or two flag files.

提交回复
热议问题