সি # তে ব্যাচ ফাইল চালানো হচ্ছে


140

আমি সি # তে একটি ব্যাচ ফাইল চালানোর চেষ্টা করছি, তবে আমি এটি করার ভাগ্য পাচ্ছি না।

এটি ইন্টারনেটে একাধিক উদাহরণ পেয়েছি, তবে এটি আমার পক্ষে কার্যকর হচ্ছে না।

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। যদি এটিতে ফাঁকা জায়গাগুলি সহ পাথ থাকে তবে আপনার চারপাশে উদ্ধৃতি লাগানো দরকার।
জন

@ জোন আমি এটি করেছি, সমস্যা নেই। আপনার ইনপুট জন্য ধন্যবাদ!
ওয়েজেল টি।

আপনার ব্যাচের ফাইলের কিছু ব্যর্থ হচ্ছে? আপনি আপনার প্রক্রিয়াটির জন্য ওয়ার্কিং ডাইরেক্টরি (বা সেই সম্পত্তি যা বলা হয়) সেট করতে চাইতে পারেন want
জোনাস

ঠিক আছে, যখন আমি কমান্ড কোডটি ম্যানুয়ালি সম্পাদন করি (শুরু -> রান করুন) এটি সঠিকভাবে চলে। আমি এখন ওয়ার্কিং ডিরেক্টরীটি যুক্ত করেছি এবং এটি সিস্টেম 32 এ সেট করেছি, তবে আমি তবুও ত্রুটি কোড: 1
ওয়েসেল টি।

উত্তর:


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। এটিকে অন্য কোনও স্থানে নিয়ে যাওয়ার চেষ্টা করুন, যেমন আপনার সম্পাদনকারীর অবস্থান। নোট করুন যে উইন্ডোজ ডিরেক্টরিতে কাস্টম ব্যাচ ফাইলগুলি বা এক্সিকিউটেবলগুলি রাখা যাইহোক খারাপ অভ্যাস।

* সম্পাদনা 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
ধন্যবাদ! এখন আমি আসলে ত্রুটিটি কী তা দেখতে পারি। "সি: \ উইন্ডোজ \ System32 \ txtmanipulator.bat অভ্যন্তরীণ বা বাহ্যিক কমান্ড, প্রোগ্রাম বা ব্যাচফাইল হিসাবে স্বীকৃত নয়" (ডাচ থেকে অনুবাদ) যা বিজোড়। কারণ আমি যখন কমান্ডলাইন থেকে টেক্সটম্যানিপুলেটর চালনা করি এটি পুরোপুরি কার্যকর হয়।
ওয়েসেল টি।

2
আমি আপনার সমস্যাটি পুনরায় তৈরি করতে সক্ষম হলাম, উত্তরের সাথে যুক্তটি দেখুন।
স্টেইনার

আমি যখন "পিজি_ডাম্প ...> ডাম্পফিল" চালাচ্ছি তখন ডাম্পফাইলে 27 জিবি ডাটাবেস ফেলে দিলে এই পদ্ধতির প্রয়োগ হবে না
পল

জমা হওয়া এড়াতে আমি কীভাবে স্ট্যান্ডার্ড আউটপুট / ত্রুটি থেকে ডেটা ধরতে পারি (প্রদত্ত ব্যাচটি বছরের পর বছর চলতে পারে এবং আমি ডেটা আসার সাথে সাথে দেখতে চাই?)
দানি

অ্যাসিনক্রোনাস পড়ার পদ্ধতিগুলি ব্যবহার করুন (সম্পাদনা 2 দেখুন) কোনও লাইন পড়ার সাথে সাথে আপনাকে পাঠ্য আউটপুট আউট করার অনুমতি দেবে।
স্টেইনার

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

এই সাধারণ লাইনটি ব্যাচ ফাইলটি কার্যকর করবে।


3
আমি কীভাবে পরামিতিগুলি পাস করতে পারি এবং কমান্ড কার্যকর করার ফলাফলটি পড়তে পারি?
জানাতবেক শার্শেভ

@ জনত্যাবকশারশেভ দেখুন আপনি
কি এটি

1
@ জনতবকশারশিয়েভ আপনি যুক্তি হিসাবে পাস করতে পারেন .. নীচের উদাহরণ দেখুন দেখুন প্রসেসস্টার্টআইএনফো তথ্য = নতুন প্রসেসস্টার্টআইএনফো ("সি: \\ ব্যাচফিলনাম.ব্যাট"); তথ্য.আরগমেন্টস = "-প্রেমিটার"; প্রক্রিয়া.স্টার্ট (তথ্য)
sk1007

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
আমার ক্ষেত্রে, একটি ব্যাচ ফাইল ব্যবহার করে অন্য ব্যাচের ফাইলকে কল করছিল ~%dp0। এটি ProcessInfo.WorkingDirectoryসংশোধন করা হচ্ছে।
সোনাতা

1
commandআপনি যদি সরাসরি বিএটি ফাইলটি কল করছেন তবে কেন পাস করবেন ?
sfarbota

বিএটি ফাইলের জন্য @ স্পারবোট আর্গুমেন্টস?
সিগড

@ সিগড আমি নিশ্চিত নই যে আপনি আমাকে কোন প্রশ্ন জিজ্ঞাসা করছেন বা আমার কোনও উত্তর সম্পর্কে পরামর্শ দিচ্ছেন কিনা। হ্যাঁ, ব্যাচের ফাইলগুলি আর্গুমেন্ট নিতে পারে। তবে আপনি যদি পরামর্শ দিচ্ছেন যে commandBAT ফাইলে আর্গুমেন্ট প্রেরণের জন্য প্যারামিটারগুলি ব্যবহৃত হতে পারে, এখানে কোডটি এটি দেখায় না। বাস্তবে এটি ব্যবহার করা হয় না। এবং যদি এটি হয় তবে এটির argumentsপরিবর্তে সম্ভবত নামকরণ করা উচিত ।
sfarbota

@sfarbota এটি একটি অনুমান ছিল। যাইহোক, কল commandব্যবহৃত হয় new ProcessStartInfo
সিগড

13

এটা ঠিক কাজ করে। আমি এটি এর মতো পরীক্ষা করেছি:

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

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

আমি উইন্ডোটি বন্ধ করে দিয়ে মন্তব্য করেছি যাতে আমি এটি চলতে দেখি।


একটি দম্পতি প্রাথমিকভাবে বিভ্রান্তিকর বিষয়গুলি পরিষ্কার করে দিয়েছিল এমন উদাহরণের জন্য আপনাকে ধন্যবাদ। পূর্ববর্তী উদাহরণগুলিকে পুনরায় ব্যবহারযোগ্য পদ্ধতিতে পরিণত করতে এটি কয়েকটি অতিরিক্ত পদক্ষেপ গ্রহণ করে এবং পূর্ববর্তী উদাহরণগুলিতে "স্ট্রিং কমান্ড" প্যারামিটারটির নাম দেওয়া উচিত আর্গ বা পরামিতি, কারণ এতে যা ঘটছে।
বিকাশকারী

7

এই নমুনা সি # কোড যা এই প্রশ্নের উত্তরের জন্য একটি ব্যাট / সেন্টিমিডি ফাইলে 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...");
}

এটিকে কাজ করার জন্য আমার ফাইলনামে পুরো পথ নির্ধারণ করা প্রয়োজন (এমনকি ওয়ার্কিং ডিরেক্টরীয়ের একই মূল পথ থাকলেও…)। আমি যদি মূল পথটি এড়িয়ে যাই তবে আমি ব্যতিক্রম পাই যে এরকম কোনও ফাইল নেই
হাওলেট

পাথটি পরীক্ষা করুন, কীটি রচনা করছেন তা যাচাই করে দেখুন এটি ম্যানুয়ালি নেই। এটি সমস্যাটি বের করতে সহায়তা করবে।
অঞ্জন কান্ত

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());
    }
}

এটিকে কাজ করার জন্য আমার ফাইলনামে পুরো পথ নির্ধারণ করা প্রয়োজন (এমনকি ওয়ার্কিং ডিরেক্টরীয়ের একই মূল পথ থাকলেও…)। আমি যদি মূল পথটি এড়িয়ে যাই তবে আমি ব্যতিক্রম পাই যে এরকম কোনও ফাইল নেই
হাওলেট

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)। আমি পৃথকভাবে ব্যাট ফাইলটি চালানোর জন্য অতিরিক্ত পদক্ষেপ নিয়ে ক্লান্ত হয়ে পড়েছিলাম এবং সি # টেস্ট সেটআপ কোডের অংশ হিসাবে ব্যাট ফাইলটি চালাতে চেয়েছিলাম। এনভায়রনমেন্ট রিসেট ব্যাচ ফাইল টেস্ট কেস ফাইলগুলিকে ইনপুট ফোল্ডারে ফিরিয়ে দেয়, আউটপুট ফোল্ডারগুলি পরিষ্কার করে ইত্যাদি পরীক্ষার জন্য সঠিক পরীক্ষার প্রারম্ভিক অবস্থানে যেতে। ফোল্ডারের নামগুলিতে ("প্রোগ্রাম ফাইলগুলি", যে কেউ?) আছে এমন ক্ষেত্রে কোটসআউন্ড পদ্ধতিটি কমান্ড লাইনের চারপাশে কোটগুলি সহজেই রাখে। এর মধ্যে যা আছে তা হ'ল: ব্যক্তিগত স্ট্রিং কোটসআউন্ড (স্ট্রিং ইনপুট) {"" \ "" + ইনপুট + "\" "; {ফেরান

আশা করি আপনার দৃশ্যটি যদি আমার মতো হয় তবে কিছু লোক এটি কার্যকর খুঁজে পেয়ে কয়েক মিনিট সাশ্রয় করবেন।


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();
    }


-1

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

আমি জানি এটি ব্যাচ ফাইল এবং পরামিতিগুলির জন্য কাজ করবে, তবে কীভাবে সি # তে ফলাফল পাবেন সে সম্পর্কে কোনও ধারণা নেই। সাধারণত, আউটপুটগুলি ব্যাচ ফাইলে সংজ্ঞায়িত করা হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.