প্রসেসবিল্ডার এবং রানটাইম.এক্সেক () এর মধ্যে পার্থক্য


97

আমি জাভা কোড থেকে একটি বাহ্যিক কমান্ড কার্যকর করার চেষ্টা করছি, কিন্তু এর মধ্যে আমি Runtime.getRuntime().exec(...)এবং এর মধ্যে একটি পার্থক্য লক্ষ্য করেছি new ProcessBuilder(...).start()

ব্যবহার করার সময় Runtime:

Process p = Runtime.getRuntime().exec(installation_path + 
                                       uninstall_path + 
                                       uninstall_command + 
                                       uninstall_arguments);
p.waitFor();

প্রস্থানভ্যালু 0 এবং কমান্ডটি শেষ হয়ে গেছে ঠিক আছে।

তবে, এর সাথে ProcessBuilder:

Process p = (new ProcessBuilder(installation_path +    
                                 uninstall_path +
                                 uninstall_command,
                                 uninstall_arguments)).start();
p.waitFor();

প্রস্থানটির মান 1001 এবং কমান্ডটি মাঝখানে শেষ হয়, যদিও এটি waitForপ্রত্যাবর্তন করে।

সমস্যাটি সমাধান করতে আমার কী করা উচিত ProcessBuilder?

উত্তর:


100

বিভিন্ন ওভারলোডগুলি Runtime.getRuntime().exec(...)স্ট্রিংগুলির একটি অ্যারে বা একটি একক স্ট্রিং নেয়। এর একক-স্ট্রিং ওভারলোডগুলি স্ট্রিংটিকে exec()অ্যারেগমেন্টের অ্যারেতে টোকনাইজ করবে, স্ট্রিং অ্যারেটিকে ওভারলোডগুলির মধ্যে একটির মধ্যে পাস করার আগে যা স্ট্রিং অ্যারে exec()নেয়। ProcessBuilderঅন্যদিকে, কনস্ট্রাক্টরগুলি কেবল একটি স্ট্রিং বা একটি স্ট্রিংয়ের একটি ভার্জেস অ্যারে নেয় List, যেখানে অ্যারে বা তালিকার প্রতিটি স্ট্রিংকে পৃথক যুক্তি হিসাবে ধরে নেওয়া হয়। যে কোনও উপায়ে, প্রাপ্ত আর্গুমেন্টগুলি তারপরে একটি স্ট্রিংয়ে যুক্ত হয়ে যায় যা কার্যকর করতে ওএসের কাছে প্রেরণ করা হয়।

সুতরাং, উদাহরণস্বরূপ, উইন্ডোজ এ,

Runtime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");

DoStuff.exeপ্রদত্ত দুটি যুক্তি সহ একটি প্রোগ্রাম পরিচালনা করবে । এই ক্ষেত্রে, কমান্ড-লাইনটি টোকেনাইজড হয়ে একসাথে ফিরে আসে। যাহোক,

ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");

, ব্যর্থ হবে যদি না সেখানে একটি প্রোগ্রাম যার নাম হতে হবে DoStuff.exe -arg1 -arg2মধ্যে C:\। এটি কারণেই কোনও টোকেনাইজেশন নেই: চালানোর কমান্ডটি ইতিমধ্যে টোকেনাইজড বলে ধরে নেওয়া হয়েছে। পরিবর্তে, আপনি ব্যবহার করা উচিত

ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");

বা বিকল্পভাবে

List<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);

এটি এখনও কার্যকর হয় না: তালিকা <স্ট্রিং> প্যারামস = java.util.Arrays.asList (ইনস্টলেশন_পথ + আনইনস্টল_প্যাথ + আনইনস্টল_কম্যান্ড, আনইনস্টল_আরগমেন্টস); প্রক্রিয়া QQ = নতুন প্রসেসবিল্ডার (প্যারাম)। স্টার্ট ();
মেয়ে

7
আমি বিশ্বাস করতে পারি না যে এই স্ট্রিং সংমিশ্রণটি কোনও অর্থ দেয়: "ইনস্টলেশন_পাথ + আনইনস্টল_প্যাথ + আনইনস্টল_কম্যান্ড"।
অ্যাঞ্জেল ওস্পিয়ার

8
Runtime.getRuntime ()। Exec (...) পায় না ডাকা যদি না করে একটি শেল স্পষ্টভাবে হুকুমে নির্দিষ্ট করা হয়েছে। সাম্প্রতিক "শেলশক" বাগ সমস্যাটি সম্পর্কে এটি একটি ভাল জিনিস thing এই উত্তরটি বিভ্রান্তিমূলক, কারণ এতে বলা হয়েছে যে cmd.exe বা সমমান (যেমন / ইউনিক্সে / বিন / বাশ) চালিত হবে, যা মনে হয় না। পরিবর্তে টোকানাইজেশন জাভা পরিবেশের ভিতরে করা হয়।
স্টিফান পল নোক

@ নোয়া ১৯৯৯: মতামতের জন্য ধন্যবাদ আমি আমার উত্তর আপডেট করেছি (আশা করি) বিষয়গুলি স্পষ্ট করার জন্য এবং বিশেষত শেলগুলির কোনও উল্লেখ মুছে ফেলা বা cmd.exe
লুক উডওয়ার্ড

Exec জন্য পার্সার হিসেবে পুরোপুরি একই কাজ করে না স্থিতিমাপ সংস্করণ পারেন, যা আমার কয়েক দিনের নেন ... জিনিসটা
ড্রিউ আইনজীবীরা Delano

19

কীভাবে Runtime.getRuntime().exec()স্ট্রিং কমান্ডটি পাস করে দেখুন ProcessBuilder। এটি একটি টোকেনাইজার ব্যবহার করে এবং স্বতন্ত্র টোকনে কমান্ডটি বিস্ফোরিত করে, তারপরে অনুরোধ করে exec(String[] cmdarray, ......)যা একটি গঠন করে ProcessBuilder

আপনি যদি নির্মাণ ProcessBuilder এককটির পরিবর্তে স্ট্রিংগুলির একটি অ্যারে দিয়ে একই ফলাফল পেয়ে যাবেন।

ProcessBuilderকন্সট্রাকটর একটি লাগে String..., vararg তাই একটি একক স্ট্রিং হিসাবে সমগ্র কমান্ড ক্ষণস্থায়ী টার্মিনালে উদ্ধৃতির মধ্যে যে কমান্ড আবাহন হিসাবে একই প্রভাব রয়েছে:

shell$ "command with args"

16

এর বাস্তবায়ন হ'ল ProcessBuilder.start()এবং এর মধ্যে কোনও পার্থক্য নেই :Runtime.exec()Runtime.exec()

public Process exec(String command) throws IOException {
    return exec(command, null, null);
}

public Process exec(String command, String[] envp, File dir)
    throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");

    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}

public Process exec(String[] cmdarray, String[] envp, File dir)
    throws IOException {
    return new ProcessBuilder(cmdarray)
        .environment(envp)
        .directory(dir)
        .start();
}

সুতরাং কোড:

List<String> list = new ArrayList<>();
new StringTokenizer(command)
.asIterator()
.forEachRemaining(str -> list.add((String) str));
new ProcessBuilder(String[])list.toArray())
            .environment(envp)
            .directory(dir)
            .start();

এর মতো হওয়া উচিত:

Runtime.exec(command)

মন্তব্যের জন্য ধন্যবাদ dave_thompson_085


4
কিন্তু প্রশ্নটি সেই পদ্ধতিটিকে কল করে না। এটি (অপ্রত্যক্ষভাবে) কল করে public Process exec(String command, String[] envp, File dir)- Stringনা String[]- যা StringTokenizerটোকেনগুলিকে একটি অ্যারেতে কল করে এবং রাখে যা পরে (অপ্রত্যক্ষভাবে) পাস করা হয় ProcessBuilder, যা years বছর আগে তিনটি উত্তর দ্বারা সঠিকভাবে বর্ণিত একটি পার্থক্য।
dave_thompson_085 21

প্রশ্নটি কত পুরনো তা বিবেচ্য নয়। তবে আমি উত্তর ঠিক করার চেষ্টা করি।
ইউজিন লোপাটকিন

আমি প্রসেসবিল্ডারের জন্য পরিবেশ নির্ধারণ করতে পারি না। আমি কেবল পরিবেশটি পেতে পারি ...
ilke মুহতারোগলু

দেখতে docs.oracle.com/javase/7/docs/api/java/lang/... পরিবেশ পদ্ধতির মাধ্যমে তাদের পাওয়ার পর সেট পরিবেশ ...
ilke Muhtaroglu

আপনি যদি আরও মনোযোগ সহকারে দেখেন তবে আপনি দেখতে পান যে ডিফল্টরূপে পরিবেশটি শূন্য।
ইউজিন লোপাটকিন

15

হ্যাঁ একটি পার্থক্য আছে।

  • Runtime.exec(String)পদ্ধতি একটি কমান্ডের স্ট্রিং যে এটি একটি কমান্ড আর্গুমেন্ট একটি ক্রম মধ্যে splits লাগে।

  • ProcessBuilderকন্সট্রাকটর স্ট্রিং একটি (ভারার্গস) অ্যারে লাগে। প্রথম স্ট্রিংটি হ'ল কমান্ডের নাম এবং এর মধ্যে বাকিগুলি আর্গুমেন্ট। (বিকল্প ধারার কনস্ট্রাক্টর রয়েছে যা স্ট্রিংয়ের একটি তালিকা নেয় তবে কমান্ড এবং আর্গুমেন্টের সমন্বয়ে একটি স্ট্রিং নেয় না))

সুতরাং আপনি প্রসেসবিল্ডারকে যা করতে বলছেন তা হ'ল একটি "কমান্ড" চালানো যাঁর নামটিতে ফাঁকা স্থান এবং অন্যান্য জাঙ্ক রয়েছে। অবশ্যই, অপারেটিং সিস্টেমটি সেই নামের সাথে একটি আদেশ সন্ধান করতে পারে না এবং কমান্ডের প্রয়োগটি ব্যর্থ হয়।


না, কোনও পার্থক্য নেই। রানটাইম.এক্সেক (স্ট্রিং) প্রসেসবিল্ডারের শর্টকাট। সমর্থিত অন্যান্য কনস্ট্রাক্টর রয়েছে।
মার্কোলপস

4
আপনি ভুল। উত্স কোড পড়ুন! Runtime.exec(cmd)কার্যকরভাবে জন্য একটি শর্টকাট Runtime.exec(cmd.split("\\s+"))ProcessBuilderবর্গ একটি কন্সট্রাকটর একটি সরাসরি সমতূল্য যে নেই Runtime.exec(cmd)। আমি আমার উত্তরটি এই পয়েন্ট করছি।
স্টিফেন সি

4
বস্তুত, যদি আপনি এটির মতো একটি ProcessBuilder instantiate: new ProcessBuilder("command arg1 arg2"), start()কল আপনি কি আশা করে দেবে না। এটি সম্ভবত ব্যর্থ হবে এবং কেবলমাত্র যদি তার নামে ফাঁকা জায়গাগুলি নিয়ে একটি আদেশ থাকে তবেই এটি সফল হবে। এটিই হ'ল সমস্যাটি যা ওপি জিজ্ঞাসা করছে!
স্টিফেন সি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.