1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

WAD Multiple TEE causese weird variable scoping?

Discussion in 'Support' started by D Broske, Dec 13, 2011.

  1. D Broske

    Joined:
    Dec 13, 2011
    Messages:
    3
    Likes Received:
    0
    Usually when I find something weird in TCC/4NT, it's some kind of CMD compatibility. But, I can't see how this could be intentional! I have repro'd in both TCC LE 13.00. 09 and 11.00.40. We are long-time 4NT users here at our shop.

    I have made a very simple repro case for this. The assignment to EXAMPLE_VAR inside the block seems to have no effect when multiple TEEs are used on the echo statement.

    As you might imagine, this code originally was meaningful and wasn't TEEing to the NUL device!

    ------------------------------------------------------
    Batch file:

    @echo off
    set EXAMPLE_VAR=0
    (
    echo This line uses TEE | tee /a nul | tee nul
    set EXAMPLE_VAR=1
    )
    echo After block: EXAMPLE_VAR = %EXAMPLE_VAR

    ---------------------------------------------------------
    Output:

    This line uses TEE
    After block: EXAMPLE_VAR = 0
     
  2. Charles Dye

    Charles Dye Super Moderator
    Staff Member

    Joined:
    May 20, 2008
    Messages:
    3,307
    Likes Received:
    39
    I think what's happening is that your second SET is being executed in one or the other of the right-hand shells. You can use more parentheses to clarify your intentions for the parser:

    Code:
    @echo off
    set EXAMPLE_VAR=0
    (
       ( echo This line uses TEE | tee /a nul | tee nul )
    set EXAMPLE_VAR=1
    )
    echo After block: EXAMPLE_VAR = %EXAMPLE_VAR
    
    Or, if you don't actually need the command group, get rid of all the parentheses.
     
  3. samintz

    samintz Scott Mintz

    Joined:
    May 20, 2008
    Messages:
    1,190
    Likes Received:
    11
    The issue is the command group as near as I can tell.
    (
    command1
    command2
    )

    is essentially: command1 & command2

    So, looking at your example, it would appear that the group is causing the set to execute inside one of the piped processes. That keeps the original value intact.

    -Scott
     
  4. D Broske

    Joined:
    Dec 13, 2011
    Messages:
    3
    Likes Received:
    0
    Thank you for your very quick replies on this one, gentlemen. This test case is very contrived; originally this was an IF group inside a FOR group.

    Scott, I like the direction you're going with this. But, why does this new version work properly? The only change is to remove the second TEE. I would expect this version to exhibit the same behavior.

    @echo off
    set EXAMPLE_VAR=0
    (
    echo This line uses TEE | tee /a nul
    set EXAMPLE_VAR=1
    )
    echo After block: EXAMPLE_VAR = %EXAMPLE_VAR
     
  5. Charles Dye

    Charles Dye Super Moderator
    Staff Member

    Joined:
    May 20, 2008
    Messages:
    3,307
    Likes Received:
    39
    I was able to replicate your issue with two FINDs instead of two TEEs. With just one FIND, the SET executes in the main shell as expected. I'm pretty sure, therefore, that it isn't multiple TEEs; it's multiple pipes.
     
  6. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,863
    Likes Received:
    83
    TCC goes through some gymnastics to move the compound argument following a pipe to execute in the parent shell instead of the child pipe shell. (Strictly speaking this isn't the technically correct way to parse the line, but 99.999% of the time the user doesn't realize that piped processes execute in a different shell and can't modify the parent environment.)

    That is impossible to do when you're nesting pipes -- TCC has no idea whether you want to execute the SET in the parent, the child pipe process, or the child of the child pipe process. (The latter is actually what you asked it to do.) You'll have to use command grouping to force the SET to the proper shell.
     
  7. D Broske

    Joined:
    Dec 13, 2011
    Messages:
    3
    Likes Received:
    0
    Thanks Rex, and everyone. This has been very educational. I really had no idea that so much magic was going on behind the scenes with multiple pipes, or groups! I certainly have learned something today.

    Sometimes, the very easy syntax of groups can lead to surprising results. Groups are not just "inline gosubs". It is easy to think of them that way because they are both EOL-delimited. But that is a very sloppy way of thinking about groups, as Scott illustrated by rephrasing my group as a single-liner with command-separators. *That* is how we should be thinking when we use multiline groups!

    Let me add one final example so that we can all see how surprising this can be. Though, this is really not very surprising considering what we've learned today.
    --------------------------------------------------
    @echo off
    set EXAMPLE_VAR=0
    (
    echo This line uses multiple pipes | tee /a nul | tee nul
    set EXAMPLE_VAR=1
    echo Inside block: EXAMPLE_VAR = %EXAMPLE_VAR
    )
    echo After block: EXAMPLE_VAR = %EXAMPLE_VAR

    ---------------------------------------------------

    This line uses multiple pipes
    Inside block: EXAMPLE_VAR = 1
    After block: EXAMPLE_VAR = 0
    ----------------------------------------------------
    Not only does the SET occur in a different shell, but also the subsequent echo! After the use of multiple pipes, the rest of this group has been relocated to a subprocess. That is pretty neato.

    Thank you all so much! I am going to take much greater care with my groups.
     
  8. rconn

    rconn Administrator
    Staff Member

    Joined:
    May 14, 2008
    Messages:
    9,863
    Likes Received:
    83
    You can in some cases (though probably not with TEE) use TCC's in-process pipes so you know everything will be happening in the original TCC session.
     

Share This Page