运行批处理文件&暂停后读取最后一行输出

本文关键字:一行 输出 最后 批处理文件 暂停 读取 运行 | 更新日期: 2023-09-27 18:14:42

我有一个web应用程序,它有一个充满批处理文件的页面,用户可以运行,查看输出,并发送输入。我的问题发生在进程遇到导致它暂停的东西时,比如暂停,或者需要用户按Y或N才能继续的问题。在这个问题中,我们将使用暂停。

这是我的批处理文件:

pause

当在windows中运行时,我得到屏幕上显示的输出"Press any key to continue…",我按enter键,它退出。但是当我的应用程序运行这个批处理文件时,我没有得到任何输出,但我知道它在等待什么,所以我按enter,然后我才看到输出"press any key to continue…"。

我在控制台应用程序中创建了一个简化版本的代码,同样的事情发生了,我得到一个空白屏幕,我按下回车键,然后我看到"按任意键继续…"

在我被要求按下键之前,我知道我是如何得到这行输出的吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
namespace BatchCaller
{
    class Program
    {
        static void Main(string[] args)
        {
            ProcessStartInfo psi = new ProcessStartInfo()
            {
                FileName = @"C:'Projects'BatchCaller'BatchCaller'Test2.bat",
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            Process proc = new Process();
            proc.StartInfo = psi;
            proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
            proc.Start();
            proc.BeginOutputReadLine();
            // Problem is not here, ignore this, just my temporary input method.
            // Problem still occurs when these two lines are removed.
            string inputText = Console.ReadLine();
            proc.StandardInput.WriteLine(inputText);
            proc.WaitForExit();
        }
        static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            // This method doesnt get called for output: "Press any key to continue..."
            // Why?
            if (e.Data != null)
                Console.WriteLine(e.Data);
        }
    }
}

运行批处理文件&暂停后读取最后一行输出

刚刚检查过,我注意到暂停不会返回到下一行文本,直到你按下键。这可能就是它没有显示的原因,因为您的代码正在寻找一行返回。与其使用ReadLine(),不如试试是否有一个可以在打印时显示所有字符的方法。(^这应该能解决你的问题,让你更实时地看到里面发生了什么)

我还以为你需要把你的:

string inputText = Console.ReadLine();             
proc.StandardInput.WriteLine(inputText); 

到OutputDataReceived处理程序。

然后在主程序中调用proc.WaitForExit(),如果运气好(我还没有测试过),应该会发生以下情况:

  • 进程的输出缓冲区被刷新
  • 你的OutputDataReceived处理程序被执行
  • 控制台。用进程的stdout
  • 控制台。读取并发送输入到进程的stdin
  • proc退出

我意识到它没有读取最后一行,因为data received事件只有在有一整行输出后才被触发,但是当它暂停或询问问题时,光标仍然在同一行上。一个新的线程可以不断地检查输出流,这是解决这个小问题的方法。

我也设法解决了我的整个问题,所以现在当我运行一个脚本时,我得到的就像一个命令提示符窗口。

这是一个非常基本的工作原理总结:

我启动一个运行批处理文件的新进程。与此同时,我启动了一个新线程,该线程不断循环,要求进程提供更多输出,并将输出存储在队列中。我的. net计时器不断检查文本队列,并将其输出到ajax面板中。我使用文本框和ajax将文本输入到流程输入和ajax面板中。我还需要大量的javascript,我不得不使用会话变量,使其顺利运行。

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
    CodeBehind="Scripts.aspx.cs" Inherits="MITool.Scripts" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <script type="text/javascript" language="javascript">
        var script = '';
        function ShowScriptModal() {
            $('#overlay').css({ width: $(document).width(), height: $(document).height(), 'display': 'block' }).animate({ opacity: 0.85 }, 0, function () { $('#scriptModal').show(); });
        }
        function ScriptInputKeypress(e) {
            if (e.keyCode == 13) {
                ScriptInput();
            }
        }
        function ScriptInput() {
            var txtInput = document.getElementById("txtInput");
            var input = txtInput.value;
            var hiddenInput = document.getElementById("hiddenInput");
            if (input == '')
                return;
            hiddenInput.value = input;
            txtInput.value = '';
        }
        function CheckForNewOutput() {
            var outputUpdatePanel = document.getElementById("OutputUpdatePanel");
            var pageScript = outputUpdatePanel.innerHTML;
            if (script != pageScript) {
                script = pageScript;
                ScrollToBottom();
            }
            setTimeout("CheckForNewOutput()", 100);
        }
        function ScrollToBottom() {
            $('#OutputPanel').scrollTop($('#OutputUpdatePanel').height());
        }
    </script>
    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true" EnablePartialRendering="true" LoadScriptsBeforeUI="true" />
    <div id="scriptModal">
        <div id="ScriptInputOutput">
            <asp:Panel ID="OutputPanel" runat="server" Width="700" Height="250" ScrollBars="Vertical"
                Style="margin: 10px auto; border: 1px solid #CCC; padding: 5px;" ClientIDMode="Static">
                <controls:ScriptOutput ID="ScriptOutputControl" runat="server" />
            </asp:Panel>
            <asp:Panel ID="InputPanel" runat="server" DefaultButton="btnScriptInput" >
                <asp:TextBox ID="txtInput" runat="server" ClientIDMode="Static" onkeypress="ScriptInputKeypress(event)" />
                <asp:HiddenField ID="hiddenInput" runat="server" ClientIDMode="Static" />
                <asp:Button ID="btnScriptInput" runat="server" Text="Script Input" ClientIDMode="Static" OnClick="btnScriptInput_Click" style="display:none" />           
                <asp:Button ID="btnExit" runat="server" CssClass="floatRight" Text="Exit" OnClick="btnExit_Click" />
            </asp:Panel>
        </div>
    </div>
    <asp:Literal ID="litScript" runat="server" />
    <ul id="breadcrumb">
        <li><a href="/dashboard.aspx">Main page</a> &gt;</li>
        <li class="current">Scripts</li>
    </ul>
    <div class="content">
        <h2>
            <asp:Label ID="lblHeader" runat="server" Text="Scripts" /></h2>
        <div class="clear">
        </div>
        <div class="table-content">
            <asp:Label ID="lblMessage" runat="server" CssClass="redMessage" />
            <asp:Repeater ID="rptScripts" runat="server" OnItemCommand="rptScripts_ItemCommand">
                <HeaderTemplate>
                    <table class="table" cellpadding="0" cellspacing="0">
                        <tr>
                            <th>
                                ID
                            </th>
                            <th>
                                Name
                            </th>
                            <th>
                                Location
                            </th>
                            <th>
                            </th>
                        </tr>
                </HeaderTemplate>
                <ItemTemplate>
                    <tr>
                        <td>
                            <%# Eval("ScriptId") %>
                        </td>
                        <td>
                            <%# Eval("Name") %>
                        </td>
                        <td>
                            <%# Eval("Path") %>
                        </td>
                        <td>
                            <asp:LinkButton ID="btnRunScript" runat="server" Text="Run" CommandName="Run" CommandArgument='<%# Eval("ScriptId") %>' />
                        </td>
                    </tr>
                </ItemTemplate>
                <FooterTemplate>
                    </table>
                </FooterTemplate>
            </asp:Repeater>
            <div>
            </div>
        </div>
    </div>
    <script type="text/javascript" language="javascript">
        CheckForNewOutput();
    </script>
</asp:Content>
// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using MITool.Data.ScriptManager;
using System.Diagnostics;
using System.IO;
using System.Web.Security;
using System.Web.Services;
using System.Collections.Concurrent;
using System.Threading;
namespace MITool
{
    public partial class Scripts : System.Web.UI.Page
    {
        ConcurrentQueue<char> ScriptOutputQueue
        {
            get
            {
                return (ConcurrentQueue<char>)Session["ScriptOutputQueue"];
            }
            set
            {
                Session["ScriptOutputQueue"] = value;
            }
        }
        Process CurrentProcess
        {
            get
            {
                return (Process)Session["CurrentProcess"];
            }
            set
            {
                Session["CurrentProcess"] = value;
            }
        }
        bool ScriptRunning
        {
            get
            {
                if (CurrentProcess == null)
                    return false;
                if (!CurrentProcess.HasExited || !CurrentProcess.StandardOutput.EndOfStream)
                    return true;
                return false;
            }
        }
        bool OutputProcessing
        {
            get
            {
                if (ScriptOutputQueue != null && ScriptOutputQueue.Count != 0)
                    return true;
                return false;
            }
        }
        Thread OutputThread;
        void Reset()
        {
            ScriptOutputControl.SetTimerEnabled(false);
            ScriptOutputControl.ClearOutputText();
            if (CurrentProcess != null && !CurrentProcess.HasExited)
                CurrentProcess.Kill();
            if (OutputThread != null && OutputThread.IsAlive)
                OutputThread.Abort();
            ScriptOutputQueue = new ConcurrentQueue<char>();
            litScript.Text = string.Empty;
            txtInput.Text = string.Empty;
        }
        void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack) return;
            Reset();
            FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
            string role = id.Ticket.UserData;
            ScriptData data = new ScriptData();
            List<Script> scripts = data.GetScriptsByRole(role);
            rptScripts.DataSource = scripts;
            rptScripts.DataBind();
        }
        protected void rptScripts_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            switch (e.CommandName)
            {
                case "Run": StartScript(Int32.Parse(e.CommandArgument.ToString()));
                    break;
            }
        }
        void StartScript(int id)
        {
            if (ScriptRunning || OutputProcessing)
                return;
            Reset();
            ScriptData data = new ScriptData();
            History history = new History()
            {
                UserName = HttpContext.Current.User.Identity.Name,
                BatchFileId = id,
                DateRun = DateTime.Now
            };
            data.CreateHistory(history);            
            Script script = data.GetScript(id);
            ProcessStartInfo psi = new ProcessStartInfo()
            {
                FileName = script.Path,
                RedirectStandardOutput = true,
                RedirectStandardInput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            CurrentProcess = new Process();
            CurrentProcess.StartInfo = psi;
            OutputThread = new Thread(Output);
            CurrentProcess.Start();
            OutputThread.Start();
            ScriptOutputControl.SetTimerEnabled(true);
            litScript.Text = "<script type='"text/javascript'" language='"javascript'">ShowScriptModal();</script>";
            SetFocus("txtInput");
        }
        void Output()
        {
            while (ScriptRunning)
            {
                var x = CurrentProcess.StandardOutput.Read();
                if (x != -1)
                    ScriptOutputQueue.Enqueue((char)x);
            }
        }
        public void btnScriptInput_Click(object sender, EventArgs e)
        {
            string input = hiddenInput.Value.ToString();
            ScriptOutputControl.Input(input);
            foreach (char x in input.ToArray())
            {
                if (CurrentProcess != null && !CurrentProcess.HasExited)
                {
                    CurrentProcess.StandardInput.Write(x);
                }
                Thread.Sleep(1);
            }
        }
        protected void btnExit_Click(object sender, EventArgs e)
        {
            Reset();
        }
    }
}
// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======//
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ScriptOutput.ascx.cs"
    Inherits="MITool.Controls.ScriptOutput" %>
<asp:Label ID="lblStats" runat="server" Style="color: Red" />
<br />
<asp:UpdatePanel ID="OutputUpdatePanel" runat="server" ClientIDMode="Static">
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="UpdateTimer" EventName="Tick" />
        <asp:AsyncPostBackTrigger ControlID="btnScriptInput" EventName="Click" />
    </Triggers>
    <ContentTemplate>
        <asp:Literal ID="litOutput" runat="server" />
    </ContentTemplate>
</asp:UpdatePanel>
<asp:Timer ID="UpdateTimer" Interval="100" runat="server" OnTick="UpdateTimer_Tick" Enabled="false" />
// ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace MITool.Controls
{
    public partial class ScriptOutput : System.Web.UI.UserControl
    {
        string Output
        {
            get
            {
                if (Session["Output"] != null)
                    return Session["Output"].ToString();
                return string.Empty;
            }
            set
            {
                Session["Output"] = value;
            }
        }
        ConcurrentQueue<char> ScriptOutputQueue
        {
            get
            {
                return (ConcurrentQueue<char>)Session["ScriptOutputQueue"];
            }
            set
            {
                Session["ScriptOutputQueue"] = value;
            }
        }
        Process CurrentProcess
        {
            get
            {
                return (Process)Session["CurrentProcess"];
            }
            set
            {
                Session["CurrentProcess"] = value;
            }
        }
        bool ScriptRunning
        {
            get
            {
                if (CurrentProcess == null)
                    return false;
                if (!CurrentProcess.HasExited || CurrentProcess.StandardOutput.Peek() != -1)
                    return true;
                return false;
            }
        }
        bool OutputProcessing
        {
            get
            {
                if (ScriptOutputQueue != null && ScriptOutputQueue.Count != 0)
                    return true;
                return false;
            }
        }
        public void SetTimerEnabled(bool enabled)
        {
            UpdateTimer.Enabled = enabled;
        }
        public void ClearOutputText()
        {
            Output = string.Empty;
            litOutput.Text = Output;
        }
        protected void UpdateTimer_Tick(object sender, EventArgs e)
        {
            ProcessOutput();
            if (!ScriptRunning && !OutputProcessing)
            {
                UpdateTimer.Enabled = false;
                Output += "<br />// SCRIPT END //<br />";
                litOutput.Text = Output;
            }
        }
        public void Input(string s) 
        {
            Output += "<br />// " + s + "<br />";
        }
        void ProcessOutput()
        {
            string s = string.Empty;
            while (ScriptOutputQueue != null && ScriptOutputQueue.Any())
            {
                char x;
                if (ScriptOutputQueue.TryDequeue(out x))
                {
                    s += x;
                }
            }
            if (s != string.Empty)
            {
                s = Server.HtmlEncode(s);
                s = s.Replace("'r'n", "<br />");
                Output += s;
            }
            litOutput.Text = Output;
        }
    }
}