C # में बैच फ़ाइल निष्पादित करना


140

मैं C # में बैच फ़ाइल निष्पादित करने का प्रयास कर रहा हूं, लेकिन मुझे ऐसा करने में कोई भाग्य नहीं मिल रहा है।

मैंने इसे करने वाले इंटरनेट पर कई उदाहरण दिए हैं, लेकिन यह मेरे लिए काम नहीं कर रहा है।

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process Process;

    ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;

    Process = Process.Start(ProcessInfo);
    Process.WaitForExit();

    ExitCode = Process.ExitCode;
    Process.Close();

    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}

कमांड स्ट्रिंग में बैच फ़ाइल (संग्रहित system32) का नाम होता है और कुछ फाइलों को इसमें हेरफेर करना चाहिए। (उदाहरण:) txtmanipulator file1.txt file2.txt file3.txt। जब मैं बैच फ़ाइल को मैन्युअल रूप से निष्पादित करता हूं, तो यह सही ढंग से काम करता है।

कोड निष्पादित करते समय, यह मुझे एक **ExitCode: 1** (Catch all for general errors)

मैं क्या गलत कर रहा हूं?


4
तुम नहीं दिखाते कि क्या commandहै। यदि इसमें रिक्त स्थान वाले रास्ते हैं, तो आपको उनके आसपास उद्धरण देने की आवश्यकता होगी।
जॉन

@ जो मैंने किया है, वह समस्या नहीं है। आपके सहयोग के लिए धन्यवाद!
वेसल टी।

क्या आपके बैच फ़ाइल में कुछ विफल हो रहा है? आप अपनी प्रक्रिया के लिए वर्कडायरेक्टरी (या जो भी संपत्ति कहते हैं) सेट करना चाह सकते हैं।
जोनास

खैर, जब मैं कोड को कमांड को मैन्युअल रूप से निष्पादित करता हूं (प्रारंभ -> रन) यह सही ढंग से चलता है। मैंने वर्किंगडायरेक्टरी को अभी जोड़ दिया है और इसे system32 पर सेट कर दिया है, लेकिन मुझे अभी भी ErrorCode मिला है: 1
Wessel T.

जवाबों:


192

यह काम करना चाहिए। आप आउटपुट और त्रुटि धाराओं की सामग्री को डंप करने की कोशिश कर सकते हैं ताकि पता चल सके कि क्या हो रहा है:

static void ExecuteCommand(string command)
{
    int exitCode;
    ProcessStartInfo processInfo;
    Process process;

    processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    // *** Redirect the output ***
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    process = Process.Start(processInfo);
    process.WaitForExit();

    // *** Read the streams ***
    // Warning: This approach can lead to deadlocks, see Edit #2
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    exitCode = process.ExitCode;

    Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
    process.Close();
}

static void Main()
{
    ExecuteCommand("echo testing");
}   

* संपादित करें *

नीचे आपकी टिप्पणी में अतिरिक्त जानकारी को देखते हुए, मैं समस्या को फिर से बनाने में सक्षम था। ऐसा लगता है कि इस व्यवहार के परिणामस्वरूप कुछ सुरक्षा सेटिंग हैं (इस बारे में विस्तार से जांच नहीं की गई है)।

यह काम करता है अगर बैच फ़ाइल में स्थित नहीं हैC:\Windows\System32 । इसे किसी अन्य स्थान पर ले जाने का प्रयास करें, उदाहरण के लिए अपने निष्पादन योग्य स्थान। ध्यान दें कि Windows निर्देशिका में कस्टम बैच फ़ाइलों या निष्पादन योग्य रखने से वैसे भी बुरा व्यवहार होता है।

* संपादित 2 * यह पता चला है कि अगर धाराओं को तुल्यकालिक रूप से पढ़ा जाता है, तो एक गतिरोध हो सकता है, या तो पहले WaitForExitया तुल्यकालन में दोनों को पढ़ने से stderrऔरstdout एक के बाद एक तुल्यकालिक रूप से ।

निम्न उदाहरण के बजाय अतुल्यकालिक पढ़ने के तरीकों का उपयोग करते समय ऐसा नहीं होना चाहिए:

static void ExecuteCommand(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    var process = Process.Start(processInfo);

    process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("output>>" + e.Data);
    process.BeginOutputReadLine();

    process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("error>>" + e.Data);
    process.BeginErrorReadLine();

    process.WaitForExit();

    Console.WriteLine("ExitCode: {0}", process.ExitCode);
    process.Close();
}

1
धन्यवाद! अब मैं वास्तव में देख सकता हूं कि त्रुटि क्या है। "C: \ Windows \ System32 \ txtmanipulator.bat को आंतरिक या बाहरी कमांड, प्रोग्राम या बैचफाइल के रूप में मान्यता नहीं दी जाती है" (डच से अनुवादित) जो कि विषम है। क्योंकि जब मैं कमांडलाइन से txtmanipulator को चलाता हूं तो यह पूरी तरह से निष्पादित होता है।
वेसल टी।

2
मैं आपकी समस्या को फिर से बनाने में सक्षम था, उत्तर के अतिरिक्त की जाँच करें।
स्टीफ़न

यह दृष्टिकोण तब लागू नहीं होता है जब मैं "pg_dump ...> डंपफाइल" चलाता हूं जो डंपफाइल को 27 जीबी डेटाबेस देता है
पॉल

मैं संचय से बचने के लिए मानक आउटपुट / त्रुटि से डेटा कैसे पकड़ सकता हूं (यह देखते हुए कि बैच सालों तक चल सकता है और मैं डेटा को देखना चाहता हूं जैसे वह आता है?)
दानी

एसिंक्रोनस रीड मेथड्स (एडिट 2 देखें) का उपयोग करके आप एक लाइन पढ़ते ही टेक्स्ट को आउटपुट कर सकेंगे।
स्टेपिनार

132
System.Diagnostics.Process.Start("c:\\batchfilename.bat");

यह सरल रेखा बैच फ़ाइल को निष्पादित करेगी।


3
मैं कैसे मापदंडों को पारित कर सकता हूं और कमांड निष्पादन का परिणाम पढ़ सकता हूं?
जनाबटब शरशेयेव

@JanatbekSharsheyev देखें कि क्या यह आप के लिए पूछना है ...
यह मेरे लिए

1
@JanatbekSharsheyev आप तर्कों के रूप में पारित कर सकते हैं .. उदाहरण के लिए नीचे देखें ProcessStartInfo जानकारी = new ProcessStartInfo ("c: \\ batchfilename.bat"); info.Arguments = "-parameter";
प्रोसेस.शार्ट

17

स्टेपिनार से कुछ बड़ी मदद के बाद यह मेरे लिए काम किया है:

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process process;

    ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;
    ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator";
    // *** Redirect the output ***
    ProcessInfo.RedirectStandardError = true;
    ProcessInfo.RedirectStandardOutput = true;

    process = Process.Start(ProcessInfo);
    process.WaitForExit();

    // *** Read the streams ***
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    ExitCode = process.ExitCode;

    MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
    process.Close();
}

1
मेरे मामले में, एक बैच फ़ाइल एक और बैच फ़ाइल का उपयोग करके कॉल कर रही थी ~%dp0ProcessInfo.WorkingDirectoryइसे निश्चित रूप से जोड़ना ।
सोनाटा

1
commandयदि आप BAT फाइल को सीधे कॉल कर रहे हैं तो पास क्यों करें ?
sfarbota

BAT फ़ाइल के लिए @sfarbota तर्क?
सिगोड

@sigod मुझे यकीन नहीं है कि अगर आप मुझसे एक सवाल पूछ रहे हैं या मेरा एक संभावित जवाब सुझा रहे हैं। हां, बैच फाइलें तर्क ले सकती हैं। लेकिन अगर आप यह सुझाव दे रहे हैं कि commandBAT फ़ाइल में तर्क भेजने के लिए मापदंडों का उपयोग किया जा सकता है, तो यह वह नहीं है जो यहाँ कोड दिखाता है। यह वास्तव में उपयोग नहीं किया जाता है। और अगर ऐसा था, तो शायद argumentsइसके बजाय इसका नाम होना चाहिए ।
15

@sfarbota यह एक धारणा थी। वैसे, कॉल commandमें उपयोग किया जाता है new ProcessStartInfo
सिगोड

13

यह बढ़िया काम करता है। मैंने इसे इस तरह से परखा:

String command = @"C:\Doit.bat";

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;

मैंने टिप्पणी की कि मैं खिड़की बंद कर रहा हूं ताकि मैं इसे चला सकूं।


उदाहरण के लिए धन्यवाद जिसने एक जोड़े को शुरू में भ्रमित करने वाले बिंदुओं को स्पष्ट किया। पूर्ववर्ती उदाहरणों को पुन: प्रयोज्य विधि में बदलने के लिए कुछ अतिरिक्त कदम उठाने पड़ते हैं, और पूर्व उदाहरणों में "स्ट्रिंग कमांड" पैरामीटर को args या पैरामीटर नाम दिया जाना चाहिए, क्योंकि इसमें क्या पारित किया जा रहा है।
डेवलपर

7

यहाँ नमूना c # कोड है जो इस प्रश्न के उत्तर के लिए एक बैट / cmd फ़ाइल में 2 पैरामीटर भेज रहा है

टिप्पणी: मैं कैसे मापदंडों को पारित कर सकता हूं और कमांड निष्पादन का परिणाम पढ़ सकता हूं?

/ @ जानतबेक शरशेयेव द्वारा

विकल्प 1: कंसोल विंडो को छिपाए बिना, तर्कों को पारित किए बिना और आउटपुट प्राप्त किए बिना

using System;
using System.Diagnostics;


namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         System.Diagnostics.Process.Start(@"c:\batchfilename.bat", "\"1st\" \"2nd\"");
        }
    }
}

विकल्प 2: कंसोल विंडो को छुपाना, तर्क पास करना और आउटपुट लेना


using System;
using System.Diagnostics;

namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         var process = new Process();
         var startinfo = new ProcessStartInfo(@"c:\batchfilename.bat", "\"1st_arg\" \"2nd_arg\" \"3rd_arg\"");
         startinfo.RedirectStandardOutput = true;
         startinfo.UseShellExecute = false;
         process.StartInfo = startinfo;
         process.OutputDataReceived += (sender, argsx) => Console.WriteLine(argsx.Data); // do whatever processing you need to do in this handler
         process.Start();
         process.BeginOutputReadLine();
         process.WaitForExit();
        }
    }
}


3

नीचे दिए गए कोड ने मेरे लिए ठीक काम किया

using System.Diagnostics;

public void ExecuteBatFile()
{
    Process proc = null;

    string _batDir = string.Format(@"C:\");
    proc = new Process();
    proc.StartInfo.WorkingDirectory = _batDir;
    proc.StartInfo.FileName = "myfile.bat";
    proc.StartInfo.CreateNoWindow = false;
    proc.Start();
    proc.WaitForExit();
    ExitCode = proc.ExitCode;
    proc.Close();
    MessageBox.Show("Bat file executed...");
}

मुझे इसे काम करने के लिए FileName में WHOLE पथ असाइन करने की आवश्यकता थी (भले ही वर्किंगडायरेरी में एक ही रूट पथ हो ...)। अगर मैं रूट पाथ
छोड़ता

पथ की जाँच करें, जो रचना कर रहा है और उसकी जाँच करें, मैन्युअल रूप से मौजूद है या नहीं। यह समस्या का पता लगाने में मदद करेगा।
अंजन कांत

2
using System.Diagnostics;

private void ExecuteBatFile()
{
    Process proc = null;
    try
    {
        string targetDir = string.Format(@"D:\mydir");   //this is where mybatch.bat lies
        proc = new Process();
        proc.StartInfo.WorkingDirectory = targetDir;
        proc.StartInfo.FileName = "lorenzo.bat";
        proc.StartInfo.Arguments = string.Format("10");  //this is argument
        proc.StartInfo.CreateNoWindow = false;
        proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;  //this is for hiding the cmd window...so execution will happen in back ground.
        proc.Start();
        proc.WaitForExit();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
    }
}

मुझे इसे काम करने के लिए FileName में WHOLE पथ असाइन करने की आवश्यकता थी (भले ही वर्किंगडायरेरी में एक ही रूट पथ हो ...)। अगर मैं रूट पाथ
छोड़ता

1

क्या आपने इसे एक व्यवस्थापक के रूप में शुरू करने की कोशिश की है? विज़ुअल स्टूडियो को व्यवस्थापक के रूप में प्रारंभ करें यदि आप इसका उपयोग करते हैं, क्योंकि .batफाइलों के साथ काम करने के लिए उन विशेषाधिकारों की आवश्यकता होती है।


0

मैं ऐसा कुछ चाहता था जो संगठन-विशिष्ट हार्ड-कोडेड स्ट्रिंग मानों के बिना अधिक उपयोग करने योग्य था। मैं निम्नलिखित को कोड के सीधे पुन: प्रयोज्य चंक के रूप में प्रस्तुत करता हूं। कॉल करते समय काम करने वाले फ़ोल्डर को निर्धारित करने और पारित करने के लिए मामूली नकारात्मक की आवश्यकता होती है।

public static void ExecuteCommand(string command, string workingFolder)
        {
            int ExitCode;
            ProcessStartInfo ProcessInfo;
            Process process;

            ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
            ProcessInfo.CreateNoWindow = true;
            ProcessInfo.UseShellExecute = false;
            ProcessInfo.WorkingDirectory = workingFolder;
            // *** Redirect the output ***
            ProcessInfo.RedirectStandardError = true;
            ProcessInfo.RedirectStandardOutput = true;

            process = Process.Start(ProcessInfo);
            process.WaitForExit();

            // *** Read the streams ***
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            ExitCode = process.ExitCode;

            MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
            MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
            MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
            process.Close();
        }

इस तरह कहा जाता है:

    // This will get the current WORKING directory (i.e. \bin\Debug)
    string workingDirectory = Environment.CurrentDirectory;
    // This will get the current PROJECT directory
    string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
    string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat");
    string workingFolder = Path.GetDirectoryName(commandToExecute);
    commandToExecute = QuotesAround(commandToExecute);
    ExecuteCommand(commandToExecute, workingFolder);

इस उदाहरण में, दृश्य स्टूडियो 2017 के भीतर, एक परीक्षण चलाने के भाग के रूप में, मैं कुछ परीक्षणों को निष्पादित करने से पहले एक पर्यावरण रीसेट बैच फ़ाइल चलाना चाहता हूं। (SpecFlow + XUnit)। मैं मैन्युअल रूप से बैट फ़ाइल को अलग से चलाने के लिए अतिरिक्त चरणों से थक गया, और बस # C सेटअप परीक्षण कोड के भाग के रूप में बैट फ़ाइल चलाना चाहता था। वातावरण रीसेट बैच फ़ाइल परीक्षण केस फाइलों को इनपुट फ़ोल्डर में वापस ले जाती है, परीक्षण के लिए उचित परीक्षण शुरू करने के लिए आउटपुट फ़ोल्डर आदि को साफ करती है। QuotesAround विधि बस कमांड लाइन के चारों ओर उद्धरण लगाती है, अगर फ़ोल्डर के नाम ("प्रोग्राम फाइल्स", कोई भी) में रिक्त स्थान हैं। " वह सब इसमें है: निजी स्ट्रिंग QuotesAround (स्ट्रिंग इनपुट) {वापसी "\" "+ इनपुट +" \ ""};

आशा है कि कुछ इसे उपयोगी पाते हैं और कुछ मिनट बचते हैं यदि आपका परिदृश्य मेरे जैसा है।


0

पहले से प्रस्तावित समाधानों के साथ, मैंने कई एनपीएम कमांड को लूप में निष्पादित करने और कंसोल विंडो पर सभी आउटपुट प्राप्त करने के लिए संघर्ष किया है।

पिछली टिप्पणियों से सबकुछ संयुक्त करने के बाद, अंततः यह काम करना शुरू कर दिया, लेकिन कोड निष्पादन प्रवाह को फिर से व्यवस्थित किया।

मैंने देखा है कि घटना की सदस्यता बहुत देर हो चुकी थी (प्रक्रिया शुरू होने के बाद) और इसलिए कुछ आउटपुट कैप्चर नहीं किए गए थे।

नीचे दिया गया कोड अब निम्नलिखित करता है:

  1. प्रक्रिया शुरू होने से पहले, घटनाओं का सदस्य, इसलिए यह सुनिश्चित करना कि कोई आउटपुट नहीं छूटा।
  2. प्रक्रिया शुरू होते ही आउटपुट से रीडिंग शुरू होती है।

कोड को गतिरोधों के खिलाफ परीक्षण किया गया है, हालांकि यह समकालिक (समय पर एक प्रक्रिया निष्पादन) है, इसलिए मैं गारंटी नहीं दे सकता कि अगर यह समानांतर में चलाया जाता है तो क्या होगा।

    static void RunCommand(string command, string workingDirectory)
    {
        Process process = new Process
        {
            StartInfo = new ProcessStartInfo("cmd.exe", $"/c {command}")
            {
                WorkingDirectory = workingDirectory,
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true
            }
        };

        process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output :: " + e.Data);

        process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error :: " + e.Data);

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

        Console.WriteLine("ExitCode: {0}", process.ExitCode);
        process.Close();
    }

0

CliWrap का उपयोग करना :

var result = await Cli.Wrap("foobar.bat").ExecuteBufferedAsync();

var exitCode = result.ExitCode;
var stdOut = result.StandardOutput;

-1

System.Diagnostics.Process.Start(BatchFileName, Parameters);

मुझे पता है कि यह बैच फ़ाइल और मापदंडों के लिए काम करेगा, लेकिन सी # में परिणाम प्राप्त करने के लिए कोई विचार नहीं है। आमतौर पर, आउटपुट बैच फ़ाइल में परिभाषित होते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.