从 C# 控制台应用程序静默 Read/Write 到 .cmd 脚本

Silently Read/Write to a .cmd script from a C# console application

我正在尝试从 C# 控制台应用程序静默读取和写入 .cmd 文件。 .cmd 文件如下所示:

ECHO OFF
set Input=""
set /p IsCustom="Do you want to create a custom deploy package ? (Y/N)"
set /p Input="Enter product name (press enter for none):"
ECHO ON
cd .\DeployScript

IF /I "%IsCustom%" == "Y" (
    nant -buildfile:Deploy.build -D:environment=Disk Deploy.LocalRelease -D:productname=%Input%
    cd ..
    GOTO END
)

nant -buildfile:Deploy.build -D:environment=Disk Deploy.NewLocalRelease -D:productname=%Input%
cd ..

:END

这是我要插入值的地方:

set /p IsCustom="Do you want to create a custom deploy package ? (Y/N)"
set /p Input="Enter product name (press enter for none):"

这是我在 C# 控制台应用程序中尝试的方法,但我无法阅读以上两个问题并写信给它们:

private static void ExecuteCmdFile()
{
    Process process = new Process();
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
    process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
    process.Exited += new System.EventHandler(process_Exited);

    process.StartInfo.FileName = Path + @"\createPackage.cmd";
    process.StartInfo.UseShellExecute = false;           
    process.StartInfo.RedirectStandardOutput = true;

    process.Start();          
    process.BeginOutputReadLine();
    process.WaitForExit();
}

static void process_Exited(object sender, EventArgs e)
{
    Console.WriteLine(string.Format("process exited with code {0}\n", ""));
}

static void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    //Console.WriteLine(e.Data + "\n");
}

我无法阅读 process_OutputDataReceived() 中的问题,也不知道如何插入值。只是想知道我是否正确 reading/writing 从 C# 应用程序到 .cmd 文件?我在这里遗漏了什么或者有其他方法吗?

处理批处理文件的 Windows 命令处理器 cmd.exe 不是为与其他进程通信而设计的。它设计用于依次执行命令和可执行文件,支持简单的 IF 条件和 GOTO 来控制 command/program 执行的顺序FOR 用于在循环中重复执行某些操作。就是这样。

我建议将批处理文件修改为这段代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "IsCustom=%~1"
if defined IsCustom goto CheckInput
%SystemRoot%\System32\choice.exe /C NY /N /M "Do you want to create a custom deploy package (Y/N)?"
if errorlevel 2 (set "IsCustom=Y") else set "IsCustom=N"

:CheckInput
set "Input=%~2"
if not defined Input goto InputPrompt
if /I "%Input%" == "/N" set "Input="
goto ProcessData

:InputPrompt
set /P "Input=Enter product name (press enter for none): "
if not defined Input goto ProcessData
set "Input=%Input:"=%"

:ProcessData
cd /D "%~dp0DeployScript"
if /I "%IsCustom%" == "Y" (
    nant -buildfile:Deploy.build -D:environment=Disk Deploy.LocalRelease -D:productname="%Input%"
    goto END
)

nant -buildfile:Deploy.build -D:environment=Disk Deploy.NewLocalRelease -D:productname="%Input%"

:END
endlocal

现在可以在没有任何参数的情况下执行批处理文件,在这种情况下,系统会提示用户两次以安全可靠的方式评估输入。

但也可以 运行 批处理文件带有来自另一个可执行文件的一个或两个参数,例如用 C# 编码的程序或来自命令提示符 window 或由另一个批处理文件调用.

第一个参数被分配给环境变量 IsCustom,它在没有任何参数或 "" 作为第一个参数执行的批处理文件中明确未定义。稍后使用的 IF 条件引用环境变量 IsCustom 的字符串值只是检查字符串值是 Y 还是 y 来执行自定义操作。作为第一个参数传递给批处理文件的任何其他参数字符串都会导致 运行 执行标准操作。

第二个参数被分配给环境变量Input,它在没有任何参数或使用""作为第二个参数执行的批处理文件中也明​​确未定义。如果第二个参数 case-insensitive 等于 /N,则批处理文件将此解释为不使用产品名称的明确请求。

Yes/No 提示是使用命令 CHOICE 完成的,如果不带任何参数或使用 [=13= 调用批处理文件,强烈建议将其用于此类选择提示] 作为第一个参数。

如果调用批处理文件时没有第二个参数或仅使用 "" 作为第二个参数,则使用 set /P 完成第二个提示。如果用户输入了一个字符串,则双引号会从输入字符串中删除,以便其余行安全可靠地处理输入字符串。

目录 DeployScript 很可能是包含批处理文件的目录的子目录,因此命令 CD 与选项 /D 一起使用如果需要,还可以更改当前驱动器,并明确地使子目录 DeployScript 当前目录独立于哪个目录是开始执行批处理文件时的当前目录。

nant 应该用文件扩展名引用,如果可能的话用完整路径引用,如果完整路径是众所周知的,因为它是相对于批处理文件路径的,或者是固定的,可以使用完全限定的文件名在批处理文件中,因为它是为外部命令完成的 CHOICE.

命令ENDLOCAL 导致初始当前目录再次成为当前目录。 SETLOCAL 将当前目录路径压入堆栈。 ENDLOCAL 从堆栈中弹出该路径并使该目录再次成为当前目录(如果在此期间没有删除,这在此处是不可能的)。因此根本不需要执行 cd ..

现在 C# 编码的应用程序可以 运行 cmd.exe 使用选项 /D/C 以及批处理文件名及其完整路径和两个参数 YN 和产品名称或 /N。不再需要与 cmd.exe 通信处理批处理文件或通过标准输入流将参数传递给 cmd.exe.[=51 的内部命令 SET =]

注:

我不太明白为什么C#Process class is used being a C# wrapper class for the Windows kernel function CreateProcess called with using the STARTUPINFO结构要运行cmd.exe来处理一个批处理文件。也可以直接通过 C# 编码程序使用 Process class 到 运行 nant,当然也可以使用批处理文件 [=133] 的任何其他可执行文件=]s 另外。 C# 编码的应用程序可以直接访问 cmd.exe 在处理批处理文件时使用的所有 Windows 库函数。因此,根据提供的有关任务的信息,我认为根本没有必要为任务使用批处理文件。

为了了解批处理文件中使用的命令及其工作原理,请打开一个 command prompt window,在那里执行以下命令,并仔细阅读每个命令显示的所有帮助页面.

  • call /? ...解释批处理文件参数引用
  • choice /?
  • cmd /?
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?