Can not redirect shell command 'read'
I have a shell script on Linux, and I use MesallionShell to redirect it, but can not print read output on screen.
#!/bin/bash
echo ""
echo ""
echo ""
echo ""
echo ""
echo "I'm #1"
read -t 3 -p "Ready for test press any key or wait for 3 s" k
echo "I'm #2"
read -t 3 -p "Ready for test press any key or wait for 3 s" k
echo "I'm #3"
read -t 3 -p "Ready for test press any key or wait for 3 s" k
echo "I'm #4"
read -t 3 -p "Ready for test press any key or wait for 3 s" k
RESULTFILE=./test.result
echo "PASS">${RESULTFILE}
ls
var command = Command.Run(path, args, opt => opt.WorkingDirectory(workingdirectory));
command.RedirectTo(Console.OpenStandardOutput());
command.RedirectFrom(Console.OpenStandardInput());
command.RedirectStandardErrorTo(Console.OpenStandardError());
await command.Task;
When I run the script directly:

When I use MesallionShell call the script:

So how to print the message in read -p "message"
read -t 3 -p "Ready for test press any key or wait for 3 s" k
@my522cn a few thoughts:
- Can you post code which shows how you set the values for
pathandargs? - Rather than awaiting the original command's task, you should chain together the sequence of redirections and await the result of the chain:
var command = Command.Run(...).RedirectTo(...).RedirectStandardErrorTo(...).RedirectFrom(...); - I wonder if you're running into internal buffering within standard out / standard error? For example, you could try the following code to redirect:
using var autoFlushWriter = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
...RedirectTo(autoFlushWriter)...
hi,
path content is the shell script what I shared. args is empty string.
Probably args should be an empty array (no arguments) unless you mean to pass the empty string as an argument.
Did you try steps 2 and 3?
Probably args should be an empty array (no arguments) unless you mean to pass the empty string as an argument.
Did you try steps 2 and 3?
No mater args is an enpty string or array, both the same. and i have tried step 2(flow.Run5) and 3(flow.Run6).
Here's the full demo code. (dotnet 6)
using CliWrap;
using CliWrap.EventStream;
using Medallion.Shell;
using System.Diagnostics;
using System.Runtime.InteropServices;
using CliWrap.Buffered;
using System.Text;
Console.WriteLine("Hello, World!");
string scriptfile;
while (true)
{
scriptfile = "try.bat";
string bat = @"@echo off
@REM echo.
echo This batch program
echo formats and checks
pause
echo new disks
@REM echo.
set /p a=a=
echo formats and checks
pause
set /p b=b=
echo %a% %b%
exit 0
";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
scriptfile = "try.sh";
bat = @"#!/bin/bash
echo """"
echo """"
echo """"
echo """"
echo """"
echo ""I'm #1""
read -t 3 -p ""Ready for test press any key or wait for 3 s"" k
echo ""I'm #2""
read -t 3 -p ""Ready for test press any key or wait for 3 s"" k
echo ""I'm #3""
read -t 3 -p ""Ready for test press any key or wait for 3 s"" k
echo ""I'm #4""
read -t 3 -p ""Ready for test press any key or wait for 3 s"" k
RESULTFILE =./ test.result
echo ""PASS"" >${ RESULTFILE}
ls
";
}
File.WriteAllText(scriptfile, bat);
Task.Run(async () =>
{
using (var flow = new TestFlow())
{
//await flow.Run();
//await flow.Run1();
//await flow.Run2();
//await flow.Run3();
//await flow.Run4();
//await flow.Run5(scriptfile);
await flow.Run6(scriptfile);
}
Console.WriteLine("\nNEXT");
}).Wait();
}
internal class TestFlow : IDisposable
{
~TestFlow()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
internal async Task Run(string scriptfile)
{
var command = Medallion.Shell.Command.Run(scriptfile);
command.RedirectFrom(Console.OpenStandardInput());
command.RedirectTo(Console.OpenStandardOutput());
//command.RedirectStandardErrorTo(Console.OpenStandardError());
var result = await command.Task;
Console.SetIn(new StreamReader(Console.OpenStandardInput()));
command.Kill();
//Console.WriteLine(command.Task.Dispose());
Console.Write("Enter 1:");
var str = Console.ReadLine(); // can not access input
Console.WriteLine(">" + str);
}
internal async Task Run1(string scriptfile)
{
var command = Medallion.Shell.Command.Run(scriptfile)
.RedirectTo(Console.OpenStandardOutput())
.RedirectFrom(Console.OpenStandardInput())
//.RedirectFrom("EXIT")
.RedirectStandardErrorTo(Console.OpenStandardError());
//command.StandardInput.PipeFromAsync(Console.OpenStandardInput(), true);
//command.RedirectTo(Console.OpenStandardOutput());
//command.StandardInput.AutoFlush = true;
//command.StandardInput.PipeFromAsync(Console.In, true);
var result = await command.Task; // can not quit
Console.SetIn(Console.In);
Console.Write("Enter 1:");
var str = Console.ReadLine();
Console.WriteLine(">" + str);
}
internal async Task Run2(string scriptfile)
{
var stdOutBuffer = Console.OpenStandardOutput();
var stdErrBuffer = Console.OpenStandardError();
var stdInpBuffer = Console.OpenStandardInput();
var result = await Cli.Wrap(scriptfile)
.WithStandardOutputPipe(PipeTarget.ToStream(stdOutBuffer))
.WithStandardErrorPipe(PipeTarget.ToStream(stdErrBuffer))
.WithStandardInputPipe(PipeSource.FromStream(stdInpBuffer))
.ExecuteAsync();
Console.Write("Enter 1:");
var str = Console.ReadLine(); // can not access input
Console.WriteLine(">" + str);
}
internal async Task Run3(string scriptfile)
{
var stdOutBuffer = Console.OpenStandardOutput();
var stdErrBuffer = Console.OpenStandardError();
var stdInpBuffer = Console.OpenStandardInput();
var wrap = Cli.Wrap(scriptfile)
.WithStandardOutputPipe(PipeTarget.ToStream(stdOutBuffer))
.WithStandardErrorPipe(PipeTarget.ToStream(stdErrBuffer))
.WithStandardInputPipe(PipeSource.FromStream(stdInpBuffer));
var result = await wrap.ExecuteBufferedAsync();
wrap.WithStandardOutputPipe(PipeTarget.Null);
wrap.WithStandardErrorPipe(PipeTarget.Null);
wrap.WithStandardInputPipe(PipeSource.Null);
Console.Write("Enter 1:");
var str = Console.ReadLine(); // can not access input
Console.WriteLine(">" + str);
}
internal async Task Run4(string scriptfile)
{
var stdOutBuffer = Console.OpenStandardOutput();
var stdErrBuffer = Console.OpenStandardError();
var stdInpBuffer = Console.OpenStandardInput();
var wrap = Cli.Wrap(scriptfile)
.WithStandardOutputPipe(PipeTarget.ToStream(stdOutBuffer))
.WithStandardErrorPipe(PipeTarget.ToStream(stdErrBuffer))
.WithStandardInputPipe(PipeSource.FromStream(stdInpBuffer));
var result = await wrap.ExecuteBufferedAsync();
Console.WriteLine(result.StandardOutput);
Console.WriteLine("Enter 1:");
var str = Console.ReadLine(); // can not access input
Console.WriteLine(">" + str);
}
internal async Task Run5(string scriptfile)
{
var command = Medallion.Shell.Command.Run(scriptfile)
.RedirectTo(Console.OpenStandardOutput())
.RedirectStandardErrorTo(Console.OpenStandardError())
.RedirectFrom(Console.OpenStandardInput());
var result = await command.Task;
Console.SetIn(Console.In);
Console.Write("Enter 1:");
var str = Console.ReadLine();
Console.WriteLine(">" + str);
while (true)
{
Console.Write("<");
Console.WriteLine(">" + Console.ReadLine());
}
}
internal async Task Run6(string scriptfile)
{
using var autoFlushWriter = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
var command = Medallion.Shell.Command.Run(scriptfile)
.RedirectTo(autoFlushWriter)
.RedirectStandardErrorTo(Console.OpenStandardError())
.RedirectFrom(Console.OpenStandardInput());
var result = await command.Task;
Console.SetIn(Console.In);
Console.Write("Enter 1:");
var str = Console.ReadLine();
Console.WriteLine(">" + str);
while (true)
{
Console.Write("<");
Console.WriteLine(">" + Console.ReadLine());
}
}
}
And one more thing, when I redirect stdin to current console, even the process exited, console.readline cannot access any inputs immediately, pls check flow.Run5
The following worked for me:
string line;
while (!command.Task.IsCompleted
&& (line = Console.ReadLine()) != null)
{
command.StandardInput.WriteLine(line);
}