【问题标题】:C#: Problem running shell commandsC#:运行 shell 命令时出现问题
【发布时间】:2009-05-03 14:17:26
【问题描述】:

我试图让 PHP 解析器运行一个页面,然后将结果返回到我的服务器,但是当我通过我的代码运行命令时,它什么也不返回。我知道该命令是正确的,因为如果我使用相同的路径手动运行它,它就可以正常工作。这是我的代码:

var p = new Process
{
      StartInfo = new ProcessStartInfo("C:\\xampp\\php\\php.exe", path)
      {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            UseShellExecute = false,
            CreateNoWindow = true
      }
};
var output = new StringWriter();
var error = new StringWriter();
p.OutputDataReceived += (sender, args) => output.WriteLine(args.Data);
p.ErrorDataReceived += (sender, args) => error.WriteLine(args.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
if (p.ExitCode != 0)
{
      throw new Exception(string.Format(
          "PHP failed with the following output:{0}{1}",
      /* {0} */ Environment.NewLine,
      /* {1} */ error.GetStringBuilder().ToString()));
}
var res = output.GetStringBuilder().ToString();
Console.WriteLine(res);

编辑: 使用这个当前代码,它会在代码中抛出异常而没有输出。

【问题讨论】:

  • 也许如果你详细解释你想要做什么,我们可以找到更好的解决方案。
  • 当你说“它什么都不返回”时,你的意思是进程运行后 res 是空的还是永远不会返回?
  • 对不起,返回一个空字符串
  • 你试过阅读标准错误吗?也许那里有一些输出?

标签: c# php shell


【解决方案1】:

设置工作目录路径

var p = new Process
            {
                StartInfo = new ProcessStartInfo("php", path)
                {
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    WorkingDirectory = workingDir
                }
            };

【讨论】:

  • 在 p.Start() 上引发异常并显示以下消息:“系统找不到指定的文件”
  • 您能详细说明您遇到的错误吗?如果找不到 php.exe,请尝试完整路径,例如:StartInfo = new ProcessStartInfo("C:\\xampp\\php\\php.exe", path)
【解决方案2】:

问题是您在程序完成之前读取输出。您需要等待程序退出来处理输出。否则,您将在解析完成之前处理输出。加入下面一行。

p.Start();
p.WaitForExit();  // New line

EDIT OP 说他们仍然有问题。

尝试删除命令的 CMD 部分。直接运行 PHP 命令即可。允许创建一个用于调试目的的窗口也可能是有益的,这样您就可以看到运行命令时可能出现的任何错误。

【讨论】:

  • Hrm,我尝试删除 cmd 部分,但它给了我一个异常,提示“文件名、目录名或卷标语法不正确”
【解决方案3】:

调用流程并捕获其输出或错误的最可靠方法是尝试以下方式:

var p = new Process {
    StartInfo = new ProcessStartInfo("php", path) {
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        UseShellExecute = false,
        CreateNoWindow = true
    }
};
var output = new StringWriter();
var error = new StringWriter();
p.OutputDataReceived += (sender, args) => output.WriteLine(args.Data);
p.ErrorDataReceived += (sender, args) => error.WriteLine(args.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
if (p.ExitCode != 0) {
    throw new Exception(string.Format(
        "PHP failed with the following output:{0}{1}",
        /* {0} */ Environment.NewLine,
        /* {1} */ error.GetStringBuilder().ToString()));
}
var res = output.GetStringBuilder().ToString();
Console.WriteLine(res);

【讨论】:

  • 好的,我试过了,我必须编辑命令部分。将其更改为“cmd”、“/c php”+路径。然后我得到这个作为错误输出:“'php'不被识别为内部或外部命令,可运行程序或批处理文件。”但奇怪的是,如果我打开命令提示符并运行它,php 命令就可以工作......
  • 尝试指定 php 可执行文件的完整绝对路径作为 ProcessStartupInfo 构造函数的第一个参数。使用“cmd”是大材小用。
  • 好的,我试过了,它抛出了异常,输出为空白。
【解决方案4】:

ReadToEnd() 只是读取流的全部内容,就像它们在那个时间点一样。鉴于您在Start() 之后立即调用它,因此流可能是空的。你有几个选择

  • 改为调用ReadLine(),但这只会读取一行
  • p.WaitForExit() 然后调用ReadToEnd(),但我不确定这是否会保持流打开。如果是这样,那么这是您的最佳选择。

【讨论】:

    【解决方案5】:

    您需要添加 p.WaitForExit();在 p.Start() 之后;否则,当您尝试读取它时,输出还没有准备好。

    【讨论】:

      【解决方案6】:

      您通过 cmd 运行 php 有什么原因吗?不能直接执行吗?

      根据我的经验,通过 .NET 执行进程是执行另一个进程的最糟糕的方式。 unix 下的 fork() 好很多。我遇到了很多问题,因此我的建议是您强烈考虑查看Process.BeginOutputReadLine() 并在阅读中走异步路线。 ReadToEnd 和 ReadToLine 可以无限期挂起,尤其是当您要捕获冗长的输出时。

      我会粘贴一个示例,但它相当冗长。

      【讨论】:

      • 我想试试这个,但我认为MSDN上的例子很差,你能把你的例子贴出来吗?
      • 我写的用来包装这一切的类正在工作。在此期间,gist 是将 Process.OutputDataReceived 设置为将字符串连接到不断增长的私有类字符串的类静态方法的类。完成执行过程后,您可以通过公共属性访问字符串。您可以对标准错误执行与标准输出相同的操作。实际上,这就是 Process 应该是的。 :)
      猜你喜欢
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      • 2022-01-12
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-02
      相关资源
      最近更新 更多