প্রসেস.স্টার্ট: আউটপুট কীভাবে পাবেন?


306

আমি আমার মনো / .NET অ্যাপ্লিকেশন থেকে একটি বাহ্যিক কমান্ড লাইন প্রোগ্রাম পরিচালনা করতে চাই। উদাহরণস্বরূপ, আমি চালাতে চাই মেনকোডার চাই । এটা কি সম্ভব:

  1. কমান্ড লাইনের শেল আউটপুট পেতে এবং এটি আমার পাঠ্য বাক্সে লিখবেন?
  2. সময় অতিবাহিত সহ একটি অগ্রগতি বার দেখানোর সংখ্যাসূচক মান পেতে?

উত্তর:


457

আপনি যখন নিজের Processঅবজেক্টটি StartInfoযথাযথভাবে তৈরি করবেন :

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

তারপরে প্রক্রিয়া শুরু করুন এবং এটি থেকে পড়ুন:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}

আপনি স্ট্রিংগুলিকে সংখ্যার মানগুলিতে রূপান্তর করতে int.Parse()বা ব্যবহার করতে পারেন int.TryParse()। আপনার পড়া স্ট্রিংগুলিতে অবৈধ সংখ্যার অক্ষর থাকলে আপনাকে প্রথমে কিছু স্ট্রিং ম্যানিপুলেশন করতে হতে পারে।


4
আমি ভাবছিলাম যে আপনি কীভাবে স্ট্যান্ডার্ডেরার মোকাবেলা করতে পারেন? বিটিডাব্লু আমি সত্যিই এই কোড স্নিপেট পছন্দ করি! সুন্দর এবং পরিষ্কার
কোডে

3
ধন্যবাদ, তবে আমি মনে করি আমি পরিষ্কার ছিলাম না: এটি করার জন্য আমাকে অন্য লুপ যুক্ত করা উচিত?
কোডে

@ কোডিয়া - আমি দেখছি উভয় স্ট্রিম EOF এ পৌঁছালে আপনি এমন একটি লুপ তৈরি করতে পারেন যা শেষ হয়। এটি কিছুটা জটিল হয়ে উঠতে পারে কারণ একটি স্ট্রিম অনিবার্যভাবে প্রথমে ইওএফকে আঘাত করবে এবং আপনি এটি থেকে আর পড়তে চান না। আপনি দুটি ভিন্ন থ্রেডে দুটি লুপ ব্যবহার করতে পারেন।
ফেরুকসিও

1
প্রবাহের শেষের অপেক্ষা না করে প্রক্রিয়াটি শেষ না হওয়া অবধি পড়া কি আরও শক্তিশালী?
গুডডোর

@ গুডোর - আমার মনে হয় না। প্রক্রিয়াটি শেষ হয়ে গেলে, এর স্ট্রিমগুলি স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যাবে। এছাড়াও, কোনও প্রক্রিয়া সমাপ্ত হওয়ার অনেক আগে তার স্ট্রিমগুলি বন্ধ করতে পারে।
ফেরুকসিও

253

আপনি আপনার আউটপুট সিঙ্ক্রোনজ বা অ্যাসিঙ্ক্রোনালি প্রক্রিয়া করতে পারেন ।

1. সিঙ্ক্রোনাস উদাহরণ

static void runCommand()
{
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.Start();
    //* Read the output (or the error)
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    string err = process.StandardError.ReadToEnd();
    Console.WriteLine(err);
    process.WaitForExit();
}

নোট করুন আউটপুট এবং ত্রুটি উভয়ই প্রক্রিয়া করা ভাল : সেগুলি পৃথকভাবে পরিচালনা করতে হবে।

(*) কিছু কমান্ডের জন্য (এখানে StartInfo.Arguments) আপনাকে অবশ্যই /c নির্দেশিকা যুক্ত করতে হবে , অন্যথায় প্রক্রিয়াটি হ'ল WaitForExit()

2. অ্যাসিঙ্ক্রোনাস উদাহরণ

static void runCommand() 
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set your output and error (asynchronous) handlers
    process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process and handlers
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

যদি আপনাকে আউটপুট নিয়ে জটিল ক্রিয়াকলাপ করার প্রয়োজন না হয় তবে আপনি আউটপুটহ্যান্ডলার পদ্ধতিটি বাইপাস করতে পারবেন, হ্যান্ডলারদের সরাসরি ইনলাইন যুক্ত করে:

//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);

2
অ্যাসিঙ্ককে ভালোবাসতে হবে! আমি VB.net মধ্যে (একটু নকলনবিসি সঙ্গে) এই কোড ব্যবহার করতে সক্ষম ছিল
রিচার্ড বার্কার

নোট 'স্ট্রিং আউটপুট = প্রক্রিয়া। স্ট্যান্ডার্ডআউটপুট। রিডটিওএন্ড ();' আউটপুট অনেক লাইন আছে যদি একটি বড় স্ট্রিং উত্পাদন করতে পারে; অ্যাসিঙ্ক উদাহরণ, এবং ফের্রুসিওর উত্তর উভয়ই আউটপুট লাইন এক এক করে প্রক্রিয়া করে।
অ্যান্ড্রু হিল

5
দ্রষ্টব্য: আপনার প্রথম (সমকালীন) পদ্ধতিটি সঠিক নয়! আপনার স্ট্যান্ডার্ডআউটপুট এবং স্ট্যান্ডার্ডএরর উভয়ই সমকালীনভাবে পড়া উচিত নয়! এটি মৃত-লকগুলি ঘটায়। তাদের মধ্যে কমপক্ষে একটি অবশ্যই অ্যাসিঙ্ক হতে হবে।
এস.স্পার্পোশন

6
প্রক্রিয়া.ওয়েটফরেক্সট () হ'ল থ্রেড ব্লকিং, সুতরাং এটি সিঙ্ক্রোনাস। উত্তরের বিষয়টি নয়, তবে আমি ভেবেছিলাম আমি এটি যুক্ত করতে পারি। প্রক্রিয়া যুক্ত করুন E সক্ষম করুনআজাইজিংসেন্টস = সত্য এবং প্রস্থানিত ইভেন্টটি সম্পূর্ণ অ্যাসিনক্রোনাস হতে ব্যবহার করুন।
টম

সরাসরি পুনর্নির্দেশ করা সম্ভব নয় কি? আমি স্যাস আউটপুট এর সমস্ত বর্ণায়ন ব্যবহার করব?
Ini

14

ঠিক আছে, যে কেউ ত্রুটি এবং আউটপুট উভয়ই পড়তে চায় , তবে অন্য উত্তরে (আমার মত) প্রদত্ত যে কোনও সমাধানের সাথে অচল হয়ে যায় , এখানে একটি সমাধান যা আমি StandardOutputসম্পত্তির জন্য এমএসডিএন ব্যাখ্যা পড়ার পরে তৈরি করেছি ।

উত্তর টি 30 এর কোডের উপর ভিত্তি করে:

static void runCommand()
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set ONLY ONE handler here.
    process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutputHandler);
    //* Start process
    process.Start();
    //* Read one element asynchronously
    process.BeginErrorReadLine();
    //* Read the other one synchronously
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process.WaitForExit();
}

static void ErrorOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

এটি যুক্ত করার জন্য ধন্যবাদ। আপনি জিজ্ঞাসা করতে পারেন আপনি কোন আদেশটি ব্যবহার করছেন?
T30

আমি সি # তে একটি অ্যাপ্লিকেশন বিকাশ করছি যা একটি মাইএসকিএলড্প.এক্সই চালু করার জন্য তৈরি করা হয়েছে, অ্যাপটি উত্পন্ন প্রতিটি বার্তাটি ব্যবহারকারীকে দেখান, এটি শেষ হয়ে যাওয়ার জন্য অপেক্ষা করুন এবং তারপরে আরও কিছু কার্য সম্পাদন করুন। আমি বুঝতে পারি না আপনি কোন ধরনের আদেশের কথা বলছেন? এই পুরো প্রশ্নটি সি # থেকে একটি প্রক্রিয়া চালু করার বিষয়ে।
কিউবারম্যান

1
আপনি যদি দুটি পৃথক হ্যান্ডলার ব্যবহার করেন তবে অচলাবস্থা পাবেন না
ওভি

উদাহরণস্বরূপ, আপনি প্রক্রিয়াটি পড়েন tand স্ট্যান্ডার্ডআউটপুট কেবল একবার ... শুরু করার ঠিক পরে, তবে প্রক্রিয়াটি চলাকালীন কেউ এটি অবিচ্ছিন্নভাবে পড়তে চাইবে, না?
ওভি

7

এটি করার আদর্শ। নেট পদ্ধতিটি প্রক্রিয়াটির স্ট্যান্ডার্ডআউটপুট স্ট্রিম থেকে পড়া to লিঙ্কযুক্ত এমএসডিএন ডক্সে একটি উদাহরণ রয়েছে। অনুরূপ, আপনার কাছ থেকে পড়তে পারেন StandardError , এবং লেখার StandardInput


5
  1. এখানে বর্ণিত হিসাবে কোনও প্রক্রিয়াটির কমান্ড লাইন শেল আউটপুট পাওয়া সম্ভব: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SstmDiagnosticProcess.aspx

  2. এটি মেনকোডার উপর নির্ভর করে। যদি এটি কমান্ড লাইনে এই স্থিতিটিকে আউটপুট করে তবে হ্যাঁ :)


4

আপনি 2 প্রক্রিয়াগুলির মাধ্যমে যোগাযোগ করতে, চেক আউট করার জন্য ভাগ করা মেমরি ব্যবহার করতে পারেন MemoryMappedFile

আপনি মূলত mmf"ব্যবহার" স্টেটমেন্ট ব্যবহার করে প্যারেন্ট প্রসেসে একটি মেমরি ম্যাপযুক্ত ফাইল তৈরি করবেন তারপরে এটি শেষ না হওয়া পর্যন্ত দ্বিতীয় প্রক্রিয়াটি তৈরি করুন এবং এটি mmfব্যবহারের ফলাফলটি লিখতে দিন BinaryWriter, তারপরে mmfপ্যারেন্ট প্রসেসটি ব্যবহার করে ফলাফলটি পড়ুন , আপনি এটি করতে পারেন mmfকমান্ড লাইন আর্গুমেন্ট বা হার্ড কোড ব্যবহার করে নামটি পাস করুন ।

প্যারেন্ট প্রসেসে ম্যাপযুক্ত ফাইলটি ব্যবহার করার সময় নিশ্চিত করুন যে পিতা-মাতার প্রক্রিয়াতে ম্যাপ করা ফাইল প্রকাশের আগে আপনি শিশু প্রক্রিয়াটি ম্যাপ করা ফাইলটিতে ফলাফল লিখতে বাধ্য করেছেন

উদাহরণ: পিতামাতার প্রক্রিয়া

    private static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("memfile", 128))
        {
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(512);
            }

            Console.WriteLine("Starting the child process");
            // Command line args are separated by a space
            Process p = Process.Start("ChildProcess.exe", "memfile");

            Console.WriteLine("Waiting child to die");

            p.WaitForExit();
            Console.WriteLine("Child died");

            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("Result:" + reader.ReadInt32());
            }
        }
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

শিশু প্রক্রিয়া

    private static void Main(string[] args)
    {
        Console.WriteLine("Child process started");
        string mmfName = args[0];

        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(mmfName))
        {
            int readValue;
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("child reading: " + (readValue = reader.ReadInt32()));
            }
            using (MemoryMappedViewStream input = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(input);
                writer.Write(readValue * 2);
            }
        }

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

এই নমুনাটি ব্যবহার করার জন্য, আপনাকে 2 টি প্রকল্পের অভ্যন্তরে একটি সমাধান তৈরি করতে হবে, তারপরে আপনি% চাইল্ডডির% / বিন / ডিবাগ থেকে শিশু প্রক্রিয়াটির বিল্ড রেজাল্ট গ্রহণ করবেন এবং এটি% প্যারেন্টডাইরেক্টরি% / বিন / ডিবাগ এ অনুলিপি করুন এবং তারপরে চালান মূল প্রকল্প

childDirএবং parentDirectoryপিসিতে আপনার প্রকল্পগুলির ফোল্ডারের নামগুলি শুভকামি :)


1

কীভাবে একটি প্রক্রিয়া চালু করবেন (যেমন একটি ব্যাট ফাইল, পার্ল স্ক্রিপ্ট, কনসোল প্রোগ্রাম) এবং এর স্ট্যান্ডার্ড আউটপুটটি উইন্ডোজ ফর্মে প্রদর্শিত হবে:

processCaller = new ProcessCaller(this);
//processCaller.FileName = @"..\..\hello.bat";
processCaller.FileName = @"commandline.exe";
processCaller.Arguments = "";
processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.Completed += new EventHandler(processCompletedOrCanceled);
processCaller.Cancelled += new EventHandler(processCompletedOrCanceled);
// processCaller.Failed += no event handler for this one, yet.

this.richTextBox1.Text = "Started function.  Please stand by.." + Environment.NewLine;

// the following function starts a process and returns immediately,
// thus allowing the form to stay responsive.
processCaller.Start();    

আপনি ProcessCallerএই লিঙ্কটিতে সন্ধান করতে পারেন : একটি প্রক্রিয়া আরম্ভ এবং এর মান আউটপুট প্রদর্শন


1

আপনি নীচের কোড ব্যবহার করে প্রক্রিয়া আউটপুট লগ করতে পারেন:

ProcessStartInfo pinfo = new ProcessStartInfo(item);
pinfo.CreateNoWindow = false;
pinfo.UseShellExecute = true;
pinfo.RedirectStandardOutput = true;
pinfo.RedirectStandardInput = true;
pinfo.RedirectStandardError = true;
pinfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
var p = Process.Start(pinfo);
p.WaitForExit();
Process process = Process.Start(new ProcessStartInfo((item + '>' + item + ".txt"))
{
    UseShellExecute = false,
    RedirectStandardOutput = true
});
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
if (process.ExitCode != 0) { 
}

1

বিজয় এবং লিনাক্সে আমার জন্য যে সমাধানটি কাজ করেছিল তা হ'ল ফোলিং

// GET api/values
        [HttpGet("cifrado/{xml}")]
        public ActionResult<IEnumerable<string>> Cifrado(String xml)
        {
            String nombreXML = DateTime.Now.ToString("ddMMyyyyhhmmss").ToString();
            String archivo = "/app/files/"+nombreXML + ".XML";
            String comando = " --armor --recipient bibankingprd@bi.com.gt  --encrypt " + archivo;
            try{
                System.IO.File.WriteAllText(archivo, xml);                
                //String comando = "C:\\GnuPG\\bin\\gpg.exe --recipient licorera@local.com --armor --encrypt C:\\Users\\Administrador\\Documents\\pruebas\\nuevo.xml ";
                ProcessStartInfo startInfo = new ProcessStartInfo() {FileName = "/usr/bin/gpg",  Arguments = comando }; 
                Process proc = new Process() { StartInfo = startInfo, };
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.RedirectStandardError = true;
                proc.Start();
                proc.WaitForExit();
                Console.WriteLine(proc.StandardOutput.ReadToEnd());
                return new string[] { "Archivo encriptado", archivo + " - "+ comando};
            }catch (Exception exception){
                return new string[] { archivo, "exception: "+exception.ToString() + " - "+ comando };
            }
        }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.