使用.NET在同一进程中执行多个命令行

69

我试图执行多个命令而不需要每次创建一个新进程。基本上,我想启动DOS命令 shell,切换到MySQL命令 shell,并执行一个命令。下面是我调用过程的方式(也在下面)。还有,在命令中如何处理 "\"?

ExecuteCommand("mysql --user=root --password=sa casemanager", 100, false);

ExecuteCommand(@"\. " + Environment.CurrentDirectory + @"\MySQL\CaseManager.sql", 100, true);

private void ExecuteCommand(string Command, int Timeout, Boolean closeProcess)
{
    ProcessStartInfo ProcessInfo;
    Process Process;

    ProcessInfo = new ProcessStartInfo("cmd.exe", "/C " + Command);
    ProcessInfo.CreateNoWindow = false;
    ProcessInfo.UseShellExecute = false;
    Process = Process.Start(ProcessInfo);
    Process.WaitForExit(Timeout);

    if (closeProcess == true) { Process.Close(); }
}
10个回答

83

你可以重定向标准输入并使用StreamWriter来写入:

        Process p = new Process();
        ProcessStartInfo info = new ProcessStartInfo();
        info.FileName = "cmd.exe";
        info.RedirectStandardInput = true;
        info.UseShellExecute = false;

        p.StartInfo = info;
        p.Start();

        using (StreamWriter sw = p.StandardInput)
        {
            if (sw.BaseStream.CanWrite)
            {
                sw.WriteLine("mysql -u root -p");
                sw.WriteLine("mypassword");
                sw.WriteLine("use mydb;");
            }
        }

1
我已经尝试过这个,但似乎进程在命令被管道传输之前就退出了。有人能指出我的错误所在或者最近几年的用法是否有变化吗? - calben
4
对我来说运行良好。也许可以将此标记为答案? - Josh
1
在公司环境中,这对我没有起作用;我猜测是因为有一些安全措施阻止了RedirectStandardInput。不过,使用&&连接符调用CMD可以解决这个问题(见下文)。 - 9swampy

62
const string strCmdText = "/C command1&command2";
Process.Start("CMD.exe", strCmdText);

3
这正是我在寻找的。它还可以与特定命令(如IF)一起使用。 - Tomáš Zato
这个也可以工作:const string strCmdText = "/C (command1)&(command2)"; - Naveen Kumar

14

你不能只是将所有命令写入 temp 文件夹中的 .cmd 文件,然后执行该文件吗?


10
不确定为什么这被标记为不是答案,仅仅因为它以问号结尾并不意味着它不是答案 =p。 - Ja͢ck
1
我在思考一个类似的解决方案,但在某些情况下(比如我的情况),可能会包含密码,所以你应该希望在错误的时刻不要崩溃并正确地删除文件...因此它也会有缺点。 - Andreas Reiff
如果你使用太多批处理文件来分发程序,人们也会感到困惑。 - Tomáš Zato

14

正如另一个答案所提到的,在较新版本的Windows中,似乎有必要读取标准输出和/或标准错误流,否则它将在命令之间停顿。一种更简洁的方法是使用异步回调来消耗流输出,而不是使用延迟:

static void RunCommands(List<string> cmds, string workingDirectory = "")
{
    var process = new Process();
    var psi = new ProcessStartInfo();
    psi.FileName = "cmd.exe";
    psi.RedirectStandardInput = true;
    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.UseShellExecute = false;
    psi.WorkingDirectory = workingDirectory;
    process.StartInfo = psi;
    process.Start();
    process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
    process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    using (StreamWriter sw = process.StandardInput)
    {
        foreach (var cmd in cmds)
        {
            sw.WriteLine (cmd);
        }
    }
    process.WaitForExit();
}

7

我更喜欢使用BAT文件来完成这项任务。

使用BAT文件可以提供更多控制,并且您可以做任何您想做的事情。

string batFileName = path + @"\" + Guid.NewGuid() + ".bat";

using (StreamWriter batFile = new StreamWriter(batFileName))
{
    batFile.WriteLine($"YOUR COMMAND");
    batFile.WriteLine($"YOUR COMMAND");
    batFile.WriteLine($"YOUR COMMAND");
}

ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe", "/c " + batFileName);
processStartInfo.UseShellExecute = true;
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Normal;

Process p = new Process();
p.StartInfo = processStartInfo;
p.Start();
p.WaitForExit();

File.Delete(batFileName);

6
ProcessStartInfo pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = "CMD";
pStartInfo.Arguments = @"/C mysql --user=root --password=sa casemanager && \. " + Environment.CurrentDirectory + @"\MySQL\CaseManager.sql"
pStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(pStartInfo);
< p > && 是告诉命令行有另一个命令需要执行的方式。 < /p >

7
如果左侧命令失败,&& 表示右侧命令将不会被执行。详情请参阅 http://support.microsoft.com/kb/279253/zh-cn。如果不需要这种行为,可以使用单个 & - Filip

3

非常有用,例如如果命令可能包含“&”符号。(我将在其中输入用户输入的文本,因此它们可能包含任何内容。使用上述解决方案会导致我的“&”被误解为“新命令”。) - Andreas Reiff

1

你也可以告诉MySQL执行给定文件中的命令,像这样:

mysql --user=root --password=sa casemanager < CaseManager.sql

0

我正在使用这些方法:

    public static Process StartCommand(params string[] commands) => StartCommand(commands, false);
    public static Process StartCommand(IEnumerable<string> commands, bool inBackground, bool runAsAdministrator = true)
    {
        Process p = new Process();
        p.StartInfo.FileName = "cmd.exe";
        if(commands.Any()) p.StartInfo.Arguments = @"/C " + string.Join("&&", commands);
        if (runAsAdministrator)
            p.StartInfo.Verb = "runas";
        if (inBackground)
        {
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        }
        p.Start();
        return p;
    }

享受...


0

在发送另一个命令之前,您需要读取输入中的所有数据!

如果没有可用的数据,您不能要求进行读取...有点糟糕,不是吗?

我的解决方案是...当要求读取时...请求读取一个大缓冲区...例如1兆字节...

并且您需要等待至少100毫秒...示例代码...

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim oProcess As New Process()
        Dim oStartInfo As New ProcessStartInfo("cmd.exe", "")
        oStartInfo.UseShellExecute = False
        oStartInfo.RedirectStandardOutput = True
        oStartInfo.RedirectStandardInput = True
        oStartInfo.CreateNoWindow = True
        oProcess.StartInfo = oStartInfo
        oProcess.Start()


        Dim Response As String = String.Empty
        Dim BuffSize As Integer = 1024 * 1024
        Dim x As Char() = New Char(BuffSize - 1) {}
        Dim bytesRead As Integer = 0


        oProcess.StandardInput.WriteLine("dir")
        Threading.Thread.Sleep(100)
        bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
        Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))




        MsgBox(Response)
        Response = String.Empty






        oProcess.StandardInput.WriteLine("dir c:\")
        Threading.Thread.Sleep(100)
        bytesRead = 0
        bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
        Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))

        MsgBox(Response)


    End Sub
End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接