Linux 下的 .net 应用程序出现问题,无法通过 shell 脚本运行
题
我正在开发一个 .net post-commit 挂钩,通过他们的 Soap SDK 将数据输入到 OnTime 中。我的钩子在 Windows 上工作得很好,但在我们的生产 RHEL4 subversion 服务器上,当从 shell 脚本调用时它不会工作。
#!/bin/sh /usr/bin/mono $1/hooks/post-commit.exe "$@"
当我使用命令行参数执行它时,它可以正常工作。当通过 shell 脚本执行时,出现以下错误:(看起来我用来获取修订日志数据的 SVN 的流程执行存在一些问题):
Unhandled Exception: System.InvalidOperationException: The process must exit before getting the requested information. at System.Diagnostics.Process.get_ExitCode () [0x0003f] in /tmp/monobuild/build/BUILD/mono-1.9.1/mcs/class/System/System.Diagnostics/Process.cs:149 at (wrapper remoting-invoke-with-check) System.Diagnostics.Process:get_ExitCode () at SVNLib.SVN.Execute (System.String sCMD, System.String sParams, System.String sComment, System.String sUserPwd, SVNLib.SVNCallback callback) [0x00000] at SVNLib.SVN.Log (System.String sUrl, Int32 nRevLow, Int32 nRevHigh, SVNLib.SVNCallback callback) [0x00000] at SVNLib.SVN.LogAsString (System.String sUrl, Int32 nRevLow, Int32 nRevHigh) [0x00000] at SVNCommit2OnTime.Program.Main (System.String[] args) [0x00000]
我尝试过使用 mkbundle
和 mkbundle2
建立一个可以被命名的独立体 post-commit
, ,但我收到不同的错误消息:
Unhandled Exception: System.ArgumentNullException: Argument cannot be null. Parameter name: Value cannot be null. at System.Guid.CheckNull (System.Object o) [0x00000] at System.Guid..ctor (System.String g) [0x00000] at SVNCommit2OnTime.Program.Main (System.String[] args) [0x00000]
任何想法为什么它可能会因 shell 脚本而失败或者捆绑版本可能有什么问题?
编辑: @爱马仕, ,我已经用 echo 试过了,看起来不错。至于 $1/hooks/post-commit.exe
, ,我尝试了带有和不带有 .net 程序集完整路径的脚本,结果相同。
编辑: @莱昂, ,我都尝试过 $1 $2
和 "$@"
具有相同的结果。它是一个颠覆后提交挂钩,它需要两个参数,因此需要将它们传递给 .net 程序集。这 "$@"
这是 mono 站点推荐的从 shell 脚本调用 .net 程序集的方法。外壳脚本 是 执行 .net 程序集并使用正确的参数,但它引发了直接从命令行运行时不会引发的异常。
编辑: @温科, ,除了类似的事情之外,我没有看到环境有任何差异 BASH_LINENO
和 BASH_SOURCE
编辑: @卢克, ,我厌倦了,但这也没有什么区别。我第一次注意到这个问题是在我的机器上从 TortoiseSVN 进行测试时(当它作为 subversion 守护进程的子进程运行时),但也发现从 hooks 目录执行脚本时得到了相同的结果(即 ./post-commit REPOS REV
, , 在哪里 post-commit
就是上面的sh脚本。正在做 mono post-commit.exe REPOS REV
工作正常。主要问题是要执行,我需要有一些名称 post-commit
以便它被调用。但它不能在 shell 脚本中工作,并且如上所述, mkbundle
没有解决不同的问题。
解决方案
某些进程在关闭标准输出后停留一段时间是正常的(即你会从它们那里得到文件结尾的读数)。你需要打电话 proc.WaitForExit()
读取所有数据之后但在检查 ExitCode 之前。
其他提示
只是一个可能有助于调试的随机想法。尝试将您的 shell 脚本更改为:
#!/bin/sh
echo /usr/bin/mono $1/hooks/post-commit.exe "$@"
检查并查看它打印的行是否与您期望它运行的命令匹配。shell 脚本中的命令行参数处理可能没有执行您想要的操作。
我不知道您对脚本的输入预期是什么,但路径之前的 $1 对我来说看起来有点不合适。
你确定要这样做吗
/usr/bin/mono $1/hooks/post-commit.exe "$@"
$@ 扩展到所有参数。“$@”扩展到所有由空格连接的参数。我怀疑你的shell脚本不正确。您没有准确说明您希望脚本执行的操作,因此这确实限制了我们提出建议的可能性。
比较 shell 中和脚本中的环境变量。
尝试将“cd $1/hooks/”放在运行单声道的行之前。该文件夹中可能有一些程序集,当您从 shell 中的该文件夹运行 mono 时可以找到这些程序集,但在运行脚本时却找不到这些程序集。
验证我的代码后 做过 从命令行工作,我发现它不再工作了!我查看了我的 .net 代码,看看是否有任何意义。
这是我所拥有的:
static public int Execute(string sCMD, string sParams, string sComment, string sUserPwd, SVNCallback callback) { System.Diagnostics.Process proc = new System.Diagnostics.Process(); proc.EnableRaisingEvents = false; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.CreateNoWindow = true; proc.StartInfo.UseShellExecute = false; proc.StartInfo.Verb = "open"; proc.StartInfo.FileName = "svn"; proc.StartInfo.Arguments = Cmd(sCMD, sParams, sComment, UserPass()); proc.Start(); int nLine = 0; string sLine = ""; while ((sLine = proc.StandardOutput.ReadLine()) != null) { ++nLine; if (callback != null) { callback.Invoke(nLine, sLine); } } int errorCode = proc.ExitCode; proc.Close(); return errorCode; }
我改变了这个:
while (!proc.HasExited) { sLine = proc.StandardOutput.ReadLine(); if (sLine != null) { ++nLine; if (callback != null) { callback.Invoke(nLine, sLine); } } } int errorCode = proc.ExitCode;
看起来该进程的停留时间比我获得输出的时间要长一些,因此 proc.ExitCode
正在抛出一个错误。