从 C# Windows 窗体内部调用的 Bash 脚本
Posted
技术标签:
【中文标题】从 C# Windows 窗体内部调用的 Bash 脚本【英文标题】:Bash Script called from inside C# Windows Forms 【发布时间】:2022-01-17 14:14:05 【问题描述】:我正在尝试从 Windows 窗体应用程序中运行 bash 脚本。我的代码如下所示:
// Command String
string flashNVS = "c:\\msys32\\usr\\bin\\env MSYSTEM=MINGW32 " +
"c:\\msys32\\usr\\bin\\bash -l -c " +
"\"cd " + unixProdPath +
" && ./provision-device-secure " + deviceId + " \"";
cmdProcess.ExecuteCommandSync(flashNVS);
使用 cmdProcess 代码:
public static void ExecuteCommandSync(object command)
flashOK = 0;
try
// create the ProcessStartInfo using "cmd" as the program to be run, and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows, and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
// The following commands are needed to redirect the standard output.
//This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
//resultString = result;
if ( (result.IndexOf("Hard resetting via RTS pin") > 0) || // Success FW Flash OR NVS Flash!
(result.IndexOf("Hash of data verified") > 0) ) // Success NVS Flash
Console.WriteLine("SUCCESS : FlashOK = 1");
flashOK = 1;
// Display the command output.
Console.WriteLine(result);
catch (Exception objException)
// Log the exception
Console.WriteLine("ExecuteCommandSync failed" + objException.Message);
文件 ./provision-device-secure 脚本做了很多事情。除了一行之外,它工作正常:
$IDF_PATH/components/esptool_py/esptool/esptool.py -p $ESPPORT --before default_reset --after no_reset write_flash 0x3E0000 mfg_config_encrypted.bin 0x3E8000 nvs_keys.bin
完全令人困惑的是,如果我直接从 git bash 内部运行脚本,它就可以正常工作。但是从 Windows 窗体应用程序内部,该行没有正确完成......我需要它作为我正在编写的 Windows 应用程序的一部分运行。关于如何调整我的代码以使其运行的任何建议?以及为什么不这样做的解释?
只是为了描述失败。在 git bash 中,它使用以下输出执行:
Created encryption keys: ===> C:\Users\thebi\esp\esp32_repo\11_SN_WI_003_WiFi\prod\keys\nvs_keys.bin
Creating NVS binary with version: V2 - Multipage Blob Support Enabled
Created NVS binary: ===> C:\Users\thebi\esp\esp32_repo\11_SN_WI_003_WiFi\prod\mfg_config_encrypted.bin
但在 windows 窗体中它只这样做:
Created encryption keys: ===> C:/Users/thebi/esp/esp32_repo/11_SN_WI_003_WiFi/prod/keys/nvs_keys.bin
Creating NVS binary with version: V2 - Multipage Blob Support Enabled
而且输出文件(mfg_config_encrypted.bin)的长度为零……
【问题讨论】:
令我惊讶的是,一方面,您构建了一个要执行的复杂命令,另一方面,您从未打印出此命令的实际内容(用于日志记录/调试)。你如何确定flashNVS
包含正确的命令?
@user1934428 添加了 Console.WriteLine(flashNVS); -> c:\msys32\usr\bin\env MSYSTEM=MINGW32 c:\msys32\usr\bin\bash -l -c "cd C:/Users/thebi/esp/esp32_repo/11_SN_WI_003_WiFi/prod/ && ./provision-device-secure test-dev "
我从未使用过 msys32,但我猜如果你通过 env
调用 bash
,你将不得不使用正斜杠来指定 bash路径,因为env
可能无法处理反斜杠。
【参考方案1】:
首先你应该引用你的参数,因为它们里面有空格。其次...我只会给你我写的课程:
public delegate void ProcessMessageDelegate(object sender, string msg);
public class ProcessManager
public event ProcessMessageDelegate OnOutputData;
public event ProcessMessageDelegate OnErrorData;
public event EventHandler OnProcessEnd;
Process process;
List<string> outputBuffer = new List<string>();
public string GetProcessOutput(string cmdName, List<string> args)
InitProcess(cmdName, args);
string result = "";
if (process.Start())
try
process.BeginOutputReadLine();
process.StandardError.ReadToEnd();
process.WaitForExit();
return OutputBufferToStr();
catch (Exception ex)
if (string.IsNullOrWhiteSpace(result))
OnErrorData?.Invoke(this, ex.Message);
return null;
else
return result;
return result;
public void RunProcessAsync(string cmdName, List<string> args)
InitProcess(cmdName, args);
if (process.Start())
process.BeginOutputReadLine();
process.StandardError.ReadToEnd();
void InitProcess(string cmdName, List<string> args)
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = cmdName;
List<string> escapedArgs = new List<string>();
foreach (var arg in args)
string validArg = arg;
if (validArg.Contains(" "))
validArg = $"\"validArg\"";
escapedArgs.Add(validArg);
psi.Arguments = string.Join(" ", escapedArgs);
psi.ErrorDialog = true;
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.CreateNoWindow = true;
process = new Process();
process.StartInfo = psi;
process.OutputDataReceived += Process_OutputDataReceived;
process.Exited += Process_Exited;
process.Disposed += Process_Disposed;
process.EnableRaisingEvents = true;
outputBuffer.Clear();
string OutputBufferToStr()
return string.Join(Environment.NewLine, outputBuffer);
private void Process_Disposed(object sender, EventArgs e)
OnProcessEnd?.Invoke(this, EventArgs.Empty);
private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
outputBuffer.Add(e.Data);
OnErrorData?.Invoke(this, e.Data);
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
outputBuffer.Add(e.Data);
OnOutputData?.Invoke(this, e.Data);
private void Process_Exited(object sender, EventArgs e)
if (process != null)
process.Dispose();
OnProcessEnd?.Invoke(this, EventArgs.Empty);
请随意使用。
现在,您有两种主要方法:
GetProcessOutput
同步运行进程并将整个输出返回给您。您只需将路径传递给进程和参数列表。
第二种方法是RunProcessAsync
- 它异步运行进程。您以相同的方式调用它,但是您必须连接到事件: OnOutputData - 每次将某些内容写入输出时都会调用它
OnErrorData - 发生错误时
OnProcessEnd - 进程何时结束。
希望你会喜欢。
【讨论】:
虽然它没有解决眼前的问题,但这是一段非常有用的代码。感谢分享。【参考方案2】:只是要把这个扔掉。我在这里非常不稳定,因为我并不真正了解这些东西的任何细节。但最终起作用的是更改命令以选择 git bash,而不是 MINW32。像这样:
string flashNVS = "\"C:\\Program Files\\Git\\git-bash.exe\" -c \"cd " + unixProdPath +
" && ./provision-device-secure test-dev > unixLog.txt \"'";
Console.WriteLine(flashNVS);
不过,我不会接受我自己的答案,因为它没有解释其中的原因。如果有人能填空,那就太好了。
【讨论】:
以上是关于从 C# Windows 窗体内部调用的 Bash 脚本的主要内容,如果未能解决你的问题,请参考以下文章