How to use chained redirections?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Aacini
Expert
Posts: 1667
Joined: 06 Dec 2011 22:15
Location: México City, México

How to use chained redirections?

#1 Post by Aacini » 17 Aug 2015 10:08

I always confuse myself when I try to manage chained redirections...

I want to achieve this:

Code: Select all

@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart  X>&Y Y>&Z  |  anyProg.exe
goto :EOF

:Restart
echo This must appear in the screen
rem This send an error message to Stderr:
verify bad
echo This should go to Stdin of anyProg.exe >&3
goto :EOF

Which values must go in X, Y and Z parts above? I only know that 1 and 3 are involved...

Antonio

PS - I think would be a good idea to post a table that show how to use this method for other numbers (4, 5, etc.) and even with a simultanous input and output redirections on numbers above 3.

Meerkat
Posts: 84
Joined: 19 Jul 2015 02:27
Location: Philippines

Re: How to use chained redirections?

#2 Post by Meerkat » 18 Aug 2015 03:07

Hmm... maybe I am wrong or I just do not understand the question (I am new into redirection), but hope this helps! :D

This code is working on me...

Code: Select all

@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart 3>&1 4>&3 5>&4 6>&5 |  ftp -n
goto :EOF

:Restart
echo open ftp.microsoft.com >&6
echo user anonymous password >&6
echo dir >&6
echo ? >&6
goto :EOF


Output:

Code: Select all

04-28-10  07:21PM       <DIR>          bussys
04-28-10  10:17PM       <DIR>          deskapps
04-28-10  11:14PM       <DIR>          developr
04-28-10  11:15PM       <DIR>          KBHelp
04-28-10  11:15PM       <DIR>          MISC
04-29-10  06:54AM       <DIR>          MISC1
04-29-10  08:47AM       <DIR>          peropsys
04-29-10  05:10PM       <DIR>          Products
04-29-10  05:13PM       <DIR>          PSS
04-29-10  05:22PM       <DIR>          ResKit
04-29-10  07:51PM       <DIR>          Services
04-30-10  08:37AM       <DIR>          Softlib
Commands may be abbreviated.  Commands are:

!               delete          literal         prompt          send
?               debug           ls              put             status
append          dir             mdelete         pwd             trace
ascii           disconnect      mdir            quit            type
bell            get             mget            quote           user
binary          glob            mkdir           recv            verbose
bye             hash            mls             remotehelp
cd              help            mput            rename
close           lcd             open            rmdir


...but scrambling the redirections above does not work on me...

Code: Select all

@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart 3>&1 4>&3 6>&5 5>&4 |  ftp -n
goto :EOF

:Restart
echo open ftp.microsoft.com >&6
echo user anonymous password >&6
echo dir >&6
echo ? >&6
goto :EOF


Output:

Code: Select all

The handle could not be duplicated
during redirection of handle 6.


My observation is that &3 must be defined first before you can use it, and same to "higher" redirection "thing" (ex. &4, &5, etc.). :roll:

Meerkat

Aacini
Expert
Posts: 1667
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: How to use chained redirections?

#3 Post by Aacini » 19 Aug 2015 10:56

Meerkat wrote:Hmm... maybe I am wrong or I just do not understand the question (I am new into redirection), but hope this helps! :D

This code is working on me...

Code: Select all

@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart 3>&1 4>&3 5>&4 6>&5 |  ftp -n
goto :EOF

:Restart
echo open ftp.microsoft.com >&6
echo user anonymous password >&6
echo dir >&6
echo ? >&6
goto :EOF


[ . . . ]


My observation is that &3 must be defined first before you can use it, and same to "higher" redirection "thing" (ex. &4, &5, etc.). :roll:

Meerkat


Meerkat, your first solution does not work, because ECHO's with no redirection and error messages send to >&2 are also send to ftp. Its easier to test this with findstr (see below).


Ok. The method below solve my problem in the sense that error messages are not send to anyProg.exe, but to the screen. However, it is an incomplete solution because both Stdout and Stderr are joined in the same stream:

Code: Select all

@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart  3>&1 1>&2  |  findstr /N /A:1E "^"
goto :EOF

:Restart
echo First line send to findstr >&3
echo This must appear in the screen
echo Another line send to findstr >&3
rem This send an error message to Stderr:
verify bad
echo Last line send to findstr >&3
goto :EOF

Antonio

dbenham
Expert
Posts: 2383
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: How to use chained redirections?

#4 Post by dbenham » 19 Aug 2015 13:16

OK, it took a while, but I finally understand your goal.

The following analysis assumes you are starting with default streams: 0 points to stdin, 1 points to stdout, 2 points to stderr, and all higher numbers are undefined. Also, stdin reads from the console, and stdout and stderr both write to the console.

When a pipe is in effect, all stdout output is piped, regardless which number it came from.

EDIT - the solution has been simplified to Aacini's original solution - it works just fine
It sounds as though you want both 1 and 2 to go to the console, and 3 to go to the pipe. You have successfully defined 3 to go to the pipe, and you have redirected 1 to stderr so both 1 and 2 appear on the console without going to the pipe. But you are concerned that 1 and 2 have been merged such that they are synonymous. Presumably you want to be able to later redirect stdin or stdout independently, and are thinking that you can't. But you can :!: :D

Code: Select all

@echo off
if "%1" equ "Restart" goto restart

"%~f0" Restart  3>&1 1>&2 | findstr /n "^"
exit /b

:restart

echo(
echo Normal
echo --------------
(
  echo This must appear in the screen
 
  rem The following error content
  verify bad
 
  echo Normal: This should go to stdin of findstr >&3
)

echo(
echo stderr to nul
echo --------------
2>nul (
  echo This must appear in the screen

  rem The following error should not appear
  verify bad

  echo stderr to nul: This should go to stdin of findstr >&3
)

echo(
echo stdout to nul
echo --------------
1>nul (
  echo This should not appear on the screen

  rem The following error should appear on the screen
  verify bad

  echo stdout to nul: This should go to stdin of findstr >&3
)

exit /b

But there is still a problem that is insurmountable - Normally stdin and stdout share the console and interleave properly based on time of output. But now the pipe also shares the console, and the pipe introduces a delay that can cause indeterminate results, thus leading to confusion.

The above code produces the following on my machine:

Code: Select all

Normal
--------------
This must appear in the screen
An incorrect parameter was
entered for the command.

stderr to nul
--------------
This must appear in the screen
1:Normal: This should go to stdin of findstr

stdout to nul
--------------
An incorrect parameter was
entered for the command.
2:stderr to nul: This should go to stdin of findstr
3:stdout to nul: This should go to stdin of findstr


All is good if the pipe output is redirected to a file, or if both stdin and stdout are redirected to files. For example:

Code: Select all

@echo off
if "%1" equ "Restart" goto restart

"%~f0" Restart  3>&1 1>&2 | findstr /n "^" >pipeOutput.txt
echo(
echo pipeOutput.txt
echo -------------
type pipeOutput.txt
exit /b

:restart

echo(
echo Normal
echo --------------
(
  echo This must appear in the screen
 
  rem The following error content
  verify bad
 
  echo Normal: This should go to stdin of findstr >&3
)

echo(
echo stderr to nul
echo --------------
2>nul (
  echo This must appear in the screen

  rem The following error should not appear
  verify bad

  echo stderr to nul: This should go to stdin of findstr >&3
)

echo(
echo stdout to nul
echo --------------
1>nul (
  echo This should not appear on the screen

  rem The following error should appear on the screen
  verify bad

  echo stdout to nul: This should go to stdin of findstr >&3
)

exit /b
--OUTPUT--

Code: Select all

Normal
--------------
This must appear in the screen
An incorrect parameter was
entered for the command.

stderr to nul
--------------
This must appear in the screen

stdout to nul
--------------
An incorrect parameter was
entered for the command.

pipeOutput.txt
-------------
1:Normal: This should go to stdin of findstr
2:stderr to nul: This should go to stdin of findstr
3:stdout to nul: This should go to stdin of findstr


Dave Benham

einstein1969
Expert
Posts: 776
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: How to use chained redirections?

#5 Post by einstein1969 » 19 Aug 2015 15:49

and why this produce 3 different results?

Code: Select all

@echo off

if "%1" neq "" goto %1

"%~F0" RestartA 1>&2 |  findstr /N /A:1E "^"
echo(&pause&echo(

"%~F0" RestartB 1>&2 |  findstr /N /A:1E "^"
echo(&pause&echo(

"%~F0" RestartC 1>&2 |  findstr /N /A:1E "^"
echo(&pause&echo(

goto :EOF


:RestartA
echo First line send to findstr >&3
echo This must appear in the screen
echo Another line send to findstr >&3
rem This send an error message to Stderr:
verify bad
echo This go on stderr 1>&2
echo Last line send to findstr >&3
goto :EOF

:RestartB
echo First line send to findstr >&4
echo This must appear in the screen
echo Another line send to findstr >&4
rem This send an error message to Stderr:
verify bad
echo This go on stderr 1>&2
echo Last line send to findstr >&4
goto :EOF

:RestartC
echo First line send to findstr >&5
echo This must appear in the screen
echo Another line send to findstr >&5
rem This send an error message to Stderr:
verify bad
echo This go on stderr 1>&2
echo Last line send to findstr >&5
goto :EOF


Code: Select all

This must appear in the screen
Parametro non valido
specificato per il comando.
This go on stderr
1:First line send to findstr
2:Another line send to findstr
3:Last line send to findstr

Premere un tasto per continuare . . .

First line send to findstr
This must appear in the screen
Another line send to findstr
Parametro non valido
specificato per il comando.
This go on stderr
Last line send to findstr

Premere un tasto per continuare . . .

Impossibile duplicare l'handle
durante il reindirizzamento dell'handle 1.
This must appear in the screen
Impossibile duplicare l'handle
durante il reindirizzamento dell'handle 1.
Parametro non valido
specificato per il comando.
This go on stderr
Impossibile duplicare l'handle
durante il reindirizzamento dell'handle 1.

Premere un tasto per continuare . . .


einstein1969

dbenham
Expert
Posts: 2383
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: How to use chained redirections?

#6 Post by dbenham » 19 Aug 2015 17:03

As jeb would say - it is "obvious" :wink:

It is simply an artifact of how redirection stores the original stream definitions. All the information you need is present at viewtopic.php?p=14612#p14612 (also read the the next post after that one).

All three Restart routines (A, B, and C) perform the same redirection upon entry. 1>&2 first stores the current definition of 1 in the first available undefined handle, which is 3. Then the 1 is redirected. So upon entry, the file handles look as follows:

1 = stderr
2 = stderr
3 = stdout
4 and above are undefined

Upon return, 1 is restored with the value within 3 (back to stdout), and then 3 is undefined again.

Now for each individual routine.

:RestartA

Output redirected to &3 simply goes to stdout, so it is piped to FINDSTR. There is more going on, but it isn't important for understanding the results of this routine.

:RestartB

1>&4 first stores the current value of 1 (stderr) in the first available undefined handle, which happens to be 4. Then 1 is redirected to the value which is in 4, so it remains stderr. So effectively 1>&4 redirects 1 to itself! The output appears on the screen, as does all stderr output. After the statement is over, 1 is restored to the value in 4 (stderr), and 4 is undefined again.

:RestartC

1>&5 stores the current value of 1 (stderr) in the first available undefined handle, which happens to be 4. Then an attempt is made to redirect 1 to the value within 5, which is undefined, so it fails with an error message sent to stderr. Then 1 is restored to the value in 4 (stderr), and 4 is undefined again.


Dave Benham

einstein1969
Expert
Posts: 776
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: How to use chained redirections?

#7 Post by einstein1969 » 21 Aug 2015 14:10

Thanks Dave!

Aacini
Expert
Posts: 1667
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: How to use chained redirections?

#8 Post by Aacini » 22 Aug 2015 13:40

dbenham wrote:OK, it took a while, but I finally understand your goal.

The following analysis assumes you are starting with default streams: 0 points to stdin, 1 points to stdout, 2 points to stderr, and all higher numbers are undefined. Also, stdin reads from the console, and stdout and stderr both write to the console.

When a pipe is in effect, all stdout output is piped, regardless which number it came from.

EDIT - the solution has been simplified to Aacini's original solution - it works just fine
It sounds as though you want both 1 and 2 to go to the console, and 3 to go to the pipe. You have successfully defined 3 to go to the pipe, and you have redirected 1 to stderr so both 1 and 2 appear on the console without going to the pipe. But you are concerned that 1 and 2 have been merged such that they are synonymous. Presumably you want to be able to later redirect stdin or stdout independently, and are thinking that you can't. But you can :!: :D

Code: Select all

. . .

But there is still a problem that is insurmountable - Normally stdin and stdout share the console and interleave properly based on time of output. But now the pipe also shares the console, and the pipe introduces a delay that can cause indeterminate results, thus leading to confusion.

[ . . . ]

Dave Benham


Thanks a lot for your analysis and tests, Dave; I didn't completed further tests on my solution. The concurrent output from both sides of the pipe is not a problem in my application; however, it still don't works...

Suppose this program:

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart  3>&1 1>&2  |  CScript //nologo //E:JScript "%~F0"
goto :EOF

:Restart
echo This appear on the screen
echo ACTION: This is a command sent to the JScript section >&3
echo This also appear on the screen
echo EXIT: This command indicate the JScript section to terminate >&3
rem Previous command is used to avoid "pipe broken" error in the JScript section
rem when this Batch file terminate
goto :EOF


@end


// JScript section

var line = WScript.Stdin.ReadLine(),
    command = line.split(" ")[0];

while ( command != "EXIT:" ) {
   if ( command == "ECHO:" ) {
      WScript.Stdout.WriteLine(line);
   } else {
      // Any other action, no screen output
   }
   line = WScript.Stdin.ReadLine();
   command = line.split(" ")[0];
}


The JScript section is an auxiliary part that receive commands from the Batch section and execute they. The usual actions of the JScript section does not send output to the screen. However, the ECHO: command request show something on the screen. If the Batch part execute this line:

Code: Select all

echo ECHO: Show this on the screen >&3

The following appear on the screen:

Code: Select all

ECHO: Show this on the screen

And now, the question is: :arrow: Is there any way that the Batch code take previous output :?:

My reasoning is that the Stdout of the right side of the pipe is a standard non-redirected stream, so the line below should redirect such output to a disk file:

Code: Select all

(echo ECHO: Show this on the screen >&3) > output.txt
set /P output= < output.txt

However, this does not work: the output still go to the screen and the file is empty.

Is there any way to make this scheme work? TIA

Antonio

dbenham
Expert
Posts: 2383
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: How to use chained redirections?

#9 Post by dbenham » 22 Aug 2015 14:18

It works fine if you send the proper ECHO: command instead of ACTION: :!: :wink:

There is no need to send an EXIT: command. Your JScript can simply ReadLine() while not AtEndOfStream. That is how my JREPL.BAT works.

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart  3>&1 1>&2  |  CScript //nologo //E:JScript "%~F0"
goto :EOF

:Restart
::>nul timeout 2 /nobreak
echo This appear on the screen
echo ECHO: This is a command sent to the JScript section >&3
echo This also appear on the screen
rem Previous command is used to avoid "pipe broken" error in the JScript section
rem when this Batch file terminate
goto :EOF


@end


// JScript section

var line, command;
while ( !WScript.StdIn.AtEndOfStream ) {
   line = WScript.Stdin.ReadLine();
   command = line.split(" ")[0];
   if ( command == "ECHO:" ) {
      WScript.Stdout.WriteLine(line);
   } else {
      // Any other action, no screen output
   }
}

Aacini
Expert
Posts: 1667
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: How to use chained redirections?

#10 Post by Aacini » 22 Aug 2015 15:50

Humm... The problem is not how to terminate the program (via EndOfStream or via EXIT: command). The goal is that the Batch code take the output from the JScript code:

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off
if "%1" equ "Restart" goto Restart

"%~F0" Restart  3>&1 1>&2  |  CScript //nologo //E:JScript "%~F0"
goto :EOF

:Restart
::>nul timeout 2 /nobreak
echo This appear on the screen
echo ECHO: This is a command sent to the JScript section >&3
echo This also appear on the screen
(echo ECHO: This line must be taken in the Batch file >&3) > output.txt
set /P output= < output.txt
echo Line taken in Batch code: "%output%"
echo Last line on screen
goto :EOF


@end


// JScript section

var line, command;
while ( !WScript.StdIn.AtEndOfStream ) {
   line = WScript.Stdin.ReadLine();
   command = line.split(" ")[0];
   if ( command == "ECHO:" ) {
      WScript.Stdout.WriteLine(line);
   } else {
      // Any other action, no screen output
   }
}

If we could make this point work, we would have a bi-directional pipe mechanism in Batch!

Antonio

dbenham
Expert
Posts: 2383
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: How to use chained redirections?

#11 Post by dbenham » 23 Aug 2015 08:59

You mean something like this :?: :)

Code: Select all

@if (@CodeSection == @Batch) @then
@echo off
if "%1" equ "Restart" goto Restart
(call )>pipe.txt
"%~F0" Restart 3>&1 1>&2 <pipe.txt | CScript //nologo //E:JScript "%~f0" >>pipe.txt
del pipe.txt
exit /b

:Restart
for %%S in (
  "Hello world."
  "I can't take it any more!"
  "EXIT"
  "Should not see this"
) do call :sendReceive %%S

:sendReceive
echo BATCH: Sending %1
>&3 echo %~1

:getInput
set "ln="
set /p "ln="
if not defined ln goto :getInput
echo BATCH: Received "%ln%"
if "%ln%" equ "OK - EXIT" exit
exit /b

@end


// JScript section

var line;
while ( !WScript.StdIn.AtEndOfStream ) {
  line = WScript.Stdin.ReadLine();
  WScript.StdErr.WriteLine('JSCRIPT: Received "'+line+'"');
  WScript.StdErr.WriteLine('JSCRIPT: Sending "OK - '+line+'"');
  WScript.StdOut.WriteLine('OK - '+line);
}

--OUTPUT--

Code: Select all

C:\test>test
BATCH: Sending "Hello world."
JSCRIPT: Received "Hello world."
JSCRIPT: Sending "OK - Hello world."
BATCH: Received "OK - Hello world."
BATCH: Sending "I can't take it any more!"
JSCRIPT: Received "I can't take it any more!"
JSCRIPT: Sending "OK - I can't take it any more!"
BATCH: Received "OK - I can't take it any more!"
BATCH: Sending "EXIT"
JSCRIPT: Received "EXIT"
JSCRIPT: Sending "OK - EXIT"
BATCH: Received "OK - EXIT"

C:\test>


Dave Benham

penpen
Expert
Posts: 1846
Joined: 23 Jun 2013 06:15
Location: Germany

Re: How to use chained redirections?

#12 Post by penpen » 23 Aug 2015 16:44

i don't like temporary files, so i created my own "chain" solution ("pipeTest.bat").
But actually it isn't very stable (in such case press ctrl+C and j + return to quit) and
also not reliable (some lines get lost), but it is a (more or less) working first sketch:

Code: Select all

@if (true == false) @then /*
@echo off
:: pipeTest.bat
if NOT "%~1" == "" goto :%~1
cls
setlocal enableExtensions disableDelayedExpansion
cscript //nologo //E:JScript "%~f0" "chain" "#%~f0# #initialize#"
endlocal
goto :eof


:initialize
setlocal enableExtensions disableDelayedExpansion
(("%~f0" "main" |  >&3 cscript //nologo //E:JScript "%~f0" "stdout")2>&1 | cscript //nologo //E:JScript "%~f0" "stderr")2>&1
endlocal
goto :eof

(((echo handle[1] & >&2 echo handle[2]) |  >&3 findstr /N "^")2>&1 | findstr /N "^")2>&1 | findstr /N "^"

:main
setlocal enableExtensions enableDelayedExpansion

for /L %%a in (1, 1, 4) do (
   echo(stdout test string %%~a
   >&2 echo(stderr test string %%~a
   set "input="
   set /P "input="
   if defined input >&2 echo(round trip finished: !input!
)
endlocal
goto :eof

*/
@end

var string = null;
if (WScript.Arguments.Unnamed.Length >= 1) {
   switch(WScript.Arguments.Unnamed.Item(0)) {
      case "readLine":
         string = WScript.StdIn.ReadLine();
         WScript.StdOut.WriteLine("stdout:" + string);
         break;
      case "stdout":
         while (!WScript.StdIn.AtEndOfStream) {
            string = WScript.StdIn.ReadLine();
            WScript.StdOut.WriteLine("stdout:" + string);
         }
         break;
      case "stderr":
         while (!WScript.StdIn.AtEndOfStream) {
            string = WScript.StdIn.ReadLine();
            WScript.StdOut.WriteLine("stderr:" + string);
         }
         break;
      case "chain":
         if (WScript.Arguments.Unnamed.Length == 2) {
            var wshShell = new ActiveXObject("WScript.Shell");
            var batch = wshShell.Exec(WScript.Arguments.Unnamed.Item(1).split('#').join('\"'));

            while (!batch.Stdout.AtEndOfStream) {
               string = batch.Stdout.ReadLine();

               if (string.indexOf("stderr:") == 0) {
                  WScript.StdErr.WriteLine(string.substring(7));
               } else if (string.indexOf("stdout:") == 0) {
//                  WScript.StdOut.WriteLine("chained:" + string.substring(7));
                  batch.StdIn.WriteLine(string.substring(7));
               } else {
//                  WScript.StdOut.WriteLine("chained[quit] Unknown Protocol error. [" + string + "]");
//                  break;
               }
            }
         }
         break;
      default:
         WScript.StdOut.WriteLine("Usage: cscript //nologo //E:JScript \"pipeTest.bat\"  [readLine|stdout|stderr|chain \"<batch> params\"]");
         WScript.Quit(1);
         break;
   }
}

WScript.Quit(0);
(I suspect the "\r\n"'s may cause problems.)

penpen

dbenham
Expert
Posts: 2383
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: How to use chained redirections?

#13 Post by dbenham » 23 Aug 2015 19:52

penpen wrote:i don't like temporary files, so i created my own "chain" solution ("pipeTest.bat").
But actually it isn't very stable (in such case press ctrl+C and j + return to quit) and
also not reliable (some lines get lost), but it is a (more or less) working first sketch:

I'm pretty sure it is impossible to achieve a stable version without a temporary file. This problem basically has the same roadblocks as a pure batch asynchronous tee script. I remember StackOverflow comments from jeb about how hard he tried without using a temp file, but was never able to achieve stable success.

Also, temp files have a very undeserved bad name. Back in the day when disk access was slow, it may have been wise to avoid them. But now they are frequently extremely efficient, and also often provide the most expedient solution, greatly reducing complexity.

Sometimes a temp file can dramatically speed things up :!: Somewhere on DosTips we have a thread that shows how processing voluminous command output via FOR /F is much faster if the output is first captured in a temp file and processed by FOR /F, rather than letting FOR /F process the command output directly.

I'm not sure I would classify any of these solutions as bi-directional pipes, but there certainly is communication going in both directions. It should be possible to achieve the same effect using pure batch. My batchTee.bat script could be modified to send communication back to the left side of the pipe in much the same way as the JScript. My SNAKE.BAT game already has bidirectional asynchronous communication between two batch processes.


Dave Benham

foxidrive
Expert
Posts: 6033
Joined: 10 Feb 2012 02:20

Re: How to use chained redirections?

#14 Post by foxidrive » 23 Aug 2015 21:42

dbenham wrote:Also, temp files have a very undeserved bad name. Back in the day when disk access was slow, it may have been wise to avoid them.


Back in the days when disk access was slow, batch commands were far simpler and and native addon utilities were rare, and you just couldn't do most things without using a temporary file!

It's funny to hear people wanting to avoid them, when the OS and programs use them all day long. :)

Aacini
Expert
Posts: 1667
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: How to use chained redirections?

#15 Post by Aacini » 23 Aug 2015 23:02

dbenham wrote:You mean something like this :?: :)

Code: Select all

@if (@CodeSection == @Batch) @then
@echo off
if "%1" equ "Restart" goto Restart
(call )>pipe.txt
"%~F0" Restart 3>&1 1>&2 <pipe.txt | CScript //nologo //E:JScript "%~f0" >>pipe.txt
del pipe.txt
exit /b

:Restart
for %%S in (
  "Hello world."
  "I can't take it any more!"
  "EXIT"
  "Should not see this"
) do call :sendReceive %%S

:sendReceive
echo BATCH: Sending %1
>&3 echo %~1

:getInput
set "ln="
set /p "ln="
if not defined ln goto :getInput
echo BATCH: Received "%ln%"
if "%ln%" equ "OK - EXIT" exit
exit /b

@end


// JScript section

var line;
while ( !WScript.StdIn.AtEndOfStream ) {
  line = WScript.Stdin.ReadLine();
  WScript.StdErr.WriteLine('JSCRIPT: Received "'+line+'"');
  WScript.StdErr.WriteLine('JSCRIPT: Sending "OK - '+line+'"');
  WScript.StdOut.WriteLine('OK - '+line);
}

--OUTPUT--

Code: Select all

C:\test>test
BATCH: Sending "Hello world."
JSCRIPT: Received "Hello world."
JSCRIPT: Sending "OK - Hello world."
BATCH: Received "OK - Hello world."
BATCH: Sending "I can't take it any more!"
JSCRIPT: Received "I can't take it any more!"
JSCRIPT: Sending "OK - I can't take it any more!"
BATCH: Received "OK - I can't take it any more!"
BATCH: Sending "EXIT"
JSCRIPT: Received "EXIT"
JSCRIPT: Sending "OK - EXIT"
BATCH: Received "OK - EXIT"

C:\test>


Dave Benham


Although your method works, it had completelly modified the behaviour of the Batch file. The goal is to have a Batch file with a standard management of the three original streams (read via 0, normal output to 1, error output to 2), that may send commands to >&3 in order to execute some actions, and that (this is the missing point) may take data send from the right side of the pipe via its Stdout. The exact requirement is dictated by my new Batch-BGI graphics library. The idea is get a value generated by the HTA window and pass it back to the Batch file.

Yes, I know that this data flow may be achieved via a disk file, but such method is too slow. I wonder if some complex manipulation of the streams redirection could give us the desired result...

Antonio

Post Reply