在Windows環境下的所謂shell程式就是dos指令行程式,比如VC的CL.exe指令行編譯器,JDK的javac編譯器,啟動java程式用的java.exe都是标準的shell程式。截獲一個shell程式的輸出是很有用的,比如說您可以自己編寫一個IDE(內建開發環境),當使用者發出編譯指令時候,你可以在背景啟動shell 調用編譯器并截獲它們的輸出,對這些輸出資訊進行分析後在更為友好的使用者界面上顯示出來。
為了友善起見,我們用C#作為本文的示範語言。
通常,系統啟動Shell程式時預設給定了3個I/O信道,标準輸入(stdin), 标準輸出stdout, 标準錯誤輸出stderr。之是以這麼區分是因為在早期的計算機系統如PDP-11的一些限制。那時沒有GUI, 将輸出分為stdout,stderr可以避免程式的調試資訊和正常輸出的資訊混雜在一起。shell程式把它們的輸出寫入标準輸出管道(stdout)、把出錯資訊寫入标準錯誤管道(stderr)。預設情況下,系統将管道的輸出直接送到螢幕,這樣一來我們就能看到應用程式運作結果了。
為了捕獲一個标準控制台應用程式的輸出,我們必須把standOutput和standError管道輸出重定向到我們自定義的管道。
下面的代碼可以啟動一個shell程式,并将其輸出截獲。
// 執行個體一:WindowsForm應用程式
// 代碼如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace CommandTest
{
public partial class FrmRunCommand : Form
{
System.IO.StreamWriter sw; // 定義輸出流 sw 作為Shell的标準輸入,即指令
System.IO.StreamReader sr; // 定義輸出流 sr 作為Shell的标準輸出,即正常結果
System.IO.StreamReader err; // 定義輸出流 err 作為Shell的錯誤輸出,即出錯結果
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psI = new System.Diagnostics.ProcessStartInfo(System.Environment.GetEnvironmentVariable("ComSpec"));
public FrmRunCommand()
{
InitializeComponent();
}
private void btnRun_Click(object sender, EventArgs e)
psI.UseShellExecute =false ;
psI.RedirectStandardInput = true;
psI.RedirectStandardOutput = true;
psI.RedirectStandardError = true;
psI.CreateNoWindow = true;
p.StartInfo = psI;
Cursor = System.Windows.Forms.Cursors.WaitCursor;
p.Start();
sw = p.StandardInput;
sr = p.StandardOutput;
err = p.StandardError;
sw.AutoFlush = true;
if(coboCommand.Text != "")
{
sw.WriteLine(coboCommand.Text);
}
else
sw.WriteLine("echo 未輸入指令");
sw.Close();
tbResult.Text = "輸出結果為:"+sr.ReadToEnd();
tbResult.Text += "\n錯誤資訊:\n"+err.ReadToEnd();
Cursor = System.Windows.Forms.Cursors.Default;
}
}
// 程式運作結果:
// 執行個體二:Asp.net程式
// 執行個體二檔案一:Default.aspx
<%@ Page Language="C#" AutoEventWireup="true" validateRequest="false" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<head runat="server">
<title>Shell程式運作測試頁</title>
</head>
<body>
<form runat="server">
<div>
請輸入指令:<asp:TextBox runat="server" Width="375px"></asp:TextBox>
<asp:Button runat="server" Text="執行指令" /><br />
<asp:TextBox runat="server" Height="343px" TextMode="MultiLine" Width="551px"></asp:TextBox>
</div>
</form>
</body>
</html>
// 執行個體二檔案二:Default.aspx.cs
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
System.IO.StreamWriter sw; // 定義輸出流 sw 作為Shell的标準輸入,即指令
System.IO.StreamReader sr; // 定義輸出流 sr 作為Shell的标準輸出,即正常結果
System.IO.StreamReader err; // 定義輸出流 err 作為Shell的錯誤輸出,即出錯結果
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo psI = new System.Diagnostics.ProcessStartInfo(System.Environment.GetEnvironmentVariable("ComSpec"));
protected void Page_Load(object sender, EventArgs e)
protected void btnCommand_Click(object sender, EventArgs e)
psI.UseShellExecute = false;
psI.RedirectStandardInput = true;
psI.RedirectStandardOutput = true;
psI.RedirectStandardError = true;
psI.CreateNoWindow = true;
p.StartInfo = psI;
p.Start();
sw = p.StandardInput;
sr = p.StandardOutput;
err = p.StandardError;
sw.AutoFlush = true;
if (tbCommand.Text != "")
sw.WriteLine(tbCommand.Text);
else
tbResult.Text = "請輸入指令";
sw.Close();
tbResult.Text = "輸出結果為:\n" + sr.ReadToEnd().ToString().Replace("\n\n", "\n");
tbResult.Text += "\n==========================================";
tbResult.Text += "\n錯誤資訊:\n" + err.ReadToEnd().ToString();
// 運作結果如下:
(以上程式均在 Microsoft Visual Studio 2005 中調試通過)