Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Pipes ... not quite right?

May
12,845
164
I never had a problem with this type of construction before. Here's v25.

Code:
v:\> timer & sort infile | findstr 3 | sort /R /O outfile & timer
Timer 1 on: 20:29:33
Timer 1 on: 20:29:34

And here's v24.

Code:
v:\> timer & sort infile | findstr 3 | sort /R /O outfile & timer
Timer 1 on: 20:31:27
Timer 1 off: 20:31:27  Elapsed: 0:00:00.12

Here's another example. Shouldn't the two PIDs be the same?

Code:
v:\> echo %_pid & sort infile | ffind /mkve"1|3" | sort /R /O outfile & echo %_pid
5756
7516
 
I always figured the command separators implicitly delineated the command groups ... that a & b | c | d & e was the same as a & (b | c | d) & e.

If that's not true, what is the default behavior? In any event, the behavior had changed recently.

Piping to a compound command doesn't make much sense to me. If it's really intended, it should be the exception and require grouping.
 
I always figured the command separators implicitly delineated the command groups ... that a & b | c | d & e was the same as a & (b | c | d) & e.

That's an incorrect assumption. There is no implicit grouping of commands, regardless of whether they're pipes, command separators, or conditional separators. A pipe is not an inferior form of command separator.
 
Your second example does not work as you expected in either v24 or v25 (without adding the necessary command group).
Yeah, I noticed that. So what's going on? Below (v24), the second timer seems to be executed by the original instance while the second "echo %_pid" does not.

Code:
v:\> timer & echo foo | grep foo | grep foo & timer
Timer 1 on: 12:57:36
foo
Timer 1 off: 12:57:36  Elapsed: 0:00:00.16

v:\> echo %_pid & echo foo | grep foo | grep foo & echo %_pid
8544
foo
1288
 
Piping to a compound command doesn't make much sense to me. If it's really intended, it should be the exception and require grouping.

That's DOS-style thinking.

When you do something like "a | b & c", what happens (TCC and CMD) is that the pipe is created, and the command processor starts another shell with the arguments "b & c". The parser does not magically preprocess the remainder of the command line and decide that "c" should really be executed in the context of "a" and not "b". (And if it did try to do that, it would have to execute "b" first to be sure that it wasn't an alias or somehow other change the remainder of the command line and/or "c".)
 
Yeah, I noticed that. So what's going on? Below (v24), the second timer seems to be executed by the original instance while the second "echo %_pid" does not.

No. The second timer is being executed by the third instance, but it's inheriting some global variables (including the timers) that were passed in shared memory by the first instance. v25 moved those variables into TLS to make everything thread-safe. So your example accidentally worked, but could just as easily have caused havoc depending on what you were executing in the pipe processes.

%_pid isn't a global variable; it's reevaluated every time it's expanded.
 
That's an incorrect assumption. There is no implicit grouping of commands, regardless of whether they're pipes, command separators, or conditional separators. A pipe is not an inferior form of command separator.
Agreed! "&" is a command separator and "|" is not. Accordingly, I see three commands here ...

Code:
a & b | c | d & e

... separated by (umm) command separators. Do a, then do b | c | d, then do e.
 
Agreed! "&" is a command separator and "|" is not. Accordingly, I see three commands here ...

Code:
a & b | c | d & e

... separated by (umm) command separators. Do a, then do b | c | d, then do e.

Your interpretation of the parsing order is not how TCC and CMD actually do it. I suggest writing a DWIM plugin to handle the command processing if you want to change the default behavior.

Pipes, command separators and conditional commands are all treated the same by the command processor. The only differences are what the parser does before and/or after executing the commands.

Command groups are there for a reason...
 
Command groups are there for a reason...
It will be no problem using command grouping all the time. But I don't like it when behavior changes. And I don't like long-held beliefs turning out to be false.

Can you please explain why

a & b | c | d & e

doesn't turn into

do a
do b | c | d
do e

and say (exactly) what it does turn into and (exactly) how?
 
Documented behavior didn't change; a bug you were accidentally exploiting was fixed.

Your malformed example is and always has been interpreted as (command lines passed to new shells):

Code:
do a
do b | c | d & e
  do c | d & e
    do d & e

e is executed in the third shell after it executes d.

If you want to change this & break a few zillion batch files & all hope of CMD compatibility, convince Microsoft to change CMD first, and I'll follow suit.
 
So, as far as the parser is concerned, &, &&, |, and || are processed the same, and from left to right ... yes/no? And these (below) are the same ... yes/no?

Code:
echo %_pid & echo foo | grep foo | grep foo & echo %_pid

Code:
echo %_pid & (echo foo | (grep foo | (grep foo & (echo %_pid))))
 
When you do something like "a | b & c", what happens (TCC and CMD) is that the pipe is created, and the command processor starts another shell with the arguments "b & c".

The second command below matches your "a | b & c". But the PID looks like it was echoed by the "a" shell.

Code:
v:\> echo %_pid
5920

v:\> echo foo | grep foo & echo %_pid
foo
5920
If the "a" shell is resolving the variable and starting "grep foo & echo 5920" I should be able to thwart it like this (and can't).

Code:
v:\> echo foo | grep foo & echo %%_pid
foo
%_pid[/code

What is actually happening?
 
The second command below matches your "a | b & c". But the PID looks like it was echoed by the "a" shell.

TCC has an ancient kludge (as in 4NT v2.0) that sends "c" back to the parent pipe process. It does not work for nested pipes.

It was added because some 4DOS users had trouble grasping the concept of true pipes and couldn't understand why their environment variables were being set in the "wrong" process.

But if you use command grouping, everything gets executed where you expect it.
 
I could not post the reply I wanted to post.

<h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>

<p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
</div>

<div class="cf-column">
<h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>

<p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
</div>
</div>
</div><!-- /.section -->

<div class="cf-error-footer cf-wrapper">
<p>
<span class="cf-footer-item">Cloudflare Ray ID: <strong>52b86609ce59cf34</strong></span>
 
[This is exactly what the site wouldn't let me post except that here, I used pictures instead of code snippets copied from the console. I don't see any dirty words in there!]

I figured there was some kind of kludge happening. My original complaint was that in

Code:
timer & command1 | command2 | command3 & timer

the second TIMER wasn't executed in the same shell as the first. You said that even in v24, where the second TIMER terminated the first one, that was only because of some inheritance of timer settings (and not because they were executed in the same shell).

If CMD compatibility is important (it's not important to me) TCC behaves differently (from CMD) when it comes to mixtures of pipes and ampersands when there's no command grouping. While I couldn't use TIMER to compare, to get a fair comparison (I hope I did) I used an external MYPID.EXE which just outputs the PID of its parent (PROCESSENTRY32::th32ParentProcessID). As far as I can tell (see below) in CMD it is impossible to get "x & y" into the right side of a pipe without grouping. Compare these two ... first CMD.

1572053243995.png


And then TCC v25.

1572053327729.png
 
I could not post the reply I wanted to post.

Why have I been blocked?

This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.

Did your post by any chance contain the string CMD‍.EXE?
 
I've had trouble with posts containing CMD‍.EXE in the past. My workaround (as you can see via copy-and-paste) is to insert an invisible extra character, so the string I'm slipping past the censor isn't quite the one you think you see.
 
I've had trouble with posts containing CMD‍.EXE in the past. My workaround (as you can see via copy-and-paste) is to insert an invisible extra character, so the string I'm slipping past the censor isn't quite the one you think you see.
Pretty sly! I wonder why it's censored in the first place.
 

Similar threads

Back
Top