जावा से लिनक्स शेल कमांड कैसे प्राप्त करें


93

मैं जावा से पुनर्निर्देशन (> और) और पाइप (!) का उपयोग करके कुछ लिनक्स कमांड निष्पादित करने का प्रयास कर रहा हूं। जावा इनवॉइस cshया bashकमांड कैसे कर सकता है ?

मैंने इसका उपयोग करने की कोशिश की:

Process p = Runtime.getRuntime().exec("shell command");

लेकिन यह पुनर्निर्देशन या पाइप के साथ संगत नहीं है।


2
catऔर cshएक दूसरे के साथ करने के लिए कुछ भी नहीं है।
बोम्बे

4
मैं अन्य कमांड्स के लिए प्रश्न को समझ सकता हूं, लेकिन बिल्ली के लिए: नरक आप सिर्फ फाइल में क्यों नहीं पढ़ते हैं?
atmocreations

8
सभी को यह पहली बार गलत लगता है - जावा का निष्पादन () कमांड निष्पादित करने के लिए अंतर्निहित सिस्टम के शेल का उपयोग नहीं करता है (जैसा कि केटीएस बताते हैं)। पुनर्निर्देशन और पाइपिंग एक वास्तविक शेल की विशेषताएं हैं और जावा के निष्पादन से उपलब्ध नहीं हैं ()।
14

stevendick: बहुत-बहुत धन्यवाद, मुझे पुनर्निर्देशन और पाइपिंग के कारण समस्याएं हो रही थीं!
नारेक

System.exit (0) अगर प्रक्रिया की जाती है, तो सशर्त जाँच के अंदर नहीं होती है, इसलिए यह हमेशा आउटपुट त्रुटियों के बिना बाहर निकल जाएगी। इस तरह की गलती से बचने के लिए, कभी ब्रेसिज़ के बिना सशर्त न लिखें।

जवाबों:


96

निष्पादन आपके शेल में एक कमांड निष्पादित नहीं करता है

प्रयत्न

Process p = Runtime.getRuntime().exec(new String[]{"csh","-c","cat /home/narek/pk.txt"});

बजाय।

संपादित करें :: मेरे पास मेरे सिस्टम पर csh नहीं है इसलिए मैंने इसके बजाय bash का उपयोग किया। निम्नलिखित ने मेरे लिए काम किया

Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ls /home/XXX"});

@Narek। उसके लिए माफ़ करना। मैंने इसे अतिरिक्त रूप से हटाकर निश्चित कर दिया है। जाहिर तौर पर इनकी जरूरत नहीं है। मेरे पास अपने सिस्टम पर csh नहीं है, लेकिन यह बैश के साथ काम करता है।
KitsuneYMG

3
जैसा कि दूसरों ने उल्लेख किया है कि यह स्वतंत्र wether होना चाहिए जो आपके पास csh या bash है, है ना?
नारेक

@Narek। यह करना चाहिए, लेकिन मुझे नहीं पता? कैसे csh तर्क संभालती है।
किट्सुएनवाईएमजी

1
धन्यवाद। यह काम किया। वास्तव में मैंने "शश" के बजाय "श" का उपयोग किया।
फर्षिद

5
चेतावनी: यह समाधान संभवतः इसके लटकने की विशिष्ट समस्या में चलेगा क्योंकि आपने इसके उत्पादन और त्रुटि धाराओं को नहीं पढ़ा है। उदाहरण के लिए: stackoverflow.com/questions/8595748/java-runtime-exec
इवगेनी सर्गेव

32

रिक्त स्थान के बजाय आदेशों और तर्कों को अलग करने के लिए ProcessBuilder का उपयोग करें। उपयोग किए गए शेल की परवाह किए बिना यह काम करना चाहिए:

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(final String[] args) throws IOException, InterruptedException {
        //Build command 
        List<String> commands = new ArrayList<String>();
        commands.add("/bin/cat");
        //Add arguments
        commands.add("/home/narek/pk.txt");
        System.out.println(commands);

        //Run macro on target
        ProcessBuilder pb = new ProcessBuilder(commands);
        pb.directory(new File("/home/narek"));
        pb.redirectErrorStream(true);
        Process process = pb.start();

        //Read output
        StringBuilder out = new StringBuilder();
        BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line = null, previous = null;
        while ((line = br.readLine()) != null)
            if (!line.equals(previous)) {
                previous = line;
                out.append(line).append('\n');
                System.out.println(line);
            }

        //Check result
        if (process.waitFor() == 0) {
            System.out.println("Success!");
            System.exit(0);
        }

        //Abnormal termination: Log command parameters and output and throw ExecutionException
        System.err.println(commands);
        System.err.println(out.toString());
        System.exit(1);
    }
}

Java.util के बाद भी। *; ठीक से आयात किया गया है जिसे चलाने के लिए मुझे ऊपर का उदाहरण नहीं मिला।
स्टीव के

@Stephan मैंने लॉगिंग स्टेटमेंट और वेरिएबल्स को हटाने के लिए ऊपर दिए गए उदाहरण कोड को अपडेट किया है जो कि पेस्ट किए गए कोड के बाहर घोषित किए गए थे, और इसे अब संकलित करना चाहिए और चलाना चाहिए। कोशिश करने के लिए स्वतंत्र महसूस करें और मुझे बताएं कि यह कैसे काम करता है।
टिम

15

स्व-निहित पद्धति बनाने के लिए @ टिम के उदाहरण पर निर्माण:

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Shell {

    /** Returns null if it failed for some reason.
     */
    public static ArrayList<String> command(final String cmdline,
    final String directory) {
        try {
            Process process = 
                new ProcessBuilder(new String[] {"bash", "-c", cmdline})
                    .redirectErrorStream(true)
                    .directory(new File(directory))
                    .start();

            ArrayList<String> output = new ArrayList<String>();
            BufferedReader br = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
            String line = null;
            while ( (line = br.readLine()) != null )
                output.add(line);

            //There should really be a timeout here.
            if (0 != process.waitFor())
                return null;

            return output;

        } catch (Exception e) {
            //Warning: doing this is no good in high quality applications.
            //Instead, present appropriate error messages to the user.
            //But it's perfectly fine for prototyping.

            return null;
        }
    }

    public static void main(String[] args) {
        test("which bash");

        test("find . -type f -printf '%T@\\\\t%p\\\\n' "
            + "| sort -n | cut -f 2- | "
            + "sed -e 's/ /\\\\\\\\ /g' | xargs ls -halt");

    }

    static void test(String cmdline) {
        ArrayList<String> output = command(cmdline, ".");
        if (null == output)
            System.out.println("\n\n\t\tCOMMAND FAILED: " + cmdline);
        else
            for (String line : output)
                System.out.println(line);

    }
}

(परीक्षण उदाहरण एक कमांड है जो सभी फाइलों को एक निर्देशिका और इसके उपनिर्देशिका में, पुनरावर्ती, कालानुक्रमिक क्रम में सूचीबद्ध करता है ।)

वैसे, अगर कोई मुझे बता सकता है कि मुझे दो और चार के बजाय चार और आठ बैकस्लैम की आवश्यकता क्यों है, तो मैं कुछ सीख सकता हूं। मैं जो गिन रहा हूं, उसकी तुलना में अनसेफ होने का एक और स्तर है।

संपादित करें: बस लिनक्स पर इसी कोड की कोशिश की, और वहाँ यह पता चला है कि मुझे टेस्ट कमांड में कई बैकस्लैम के रूप में आधे की आवश्यकता है! (यह है: दो और चार की अपेक्षित संख्या।) अब यह सिर्फ अजीब नहीं है, यह एक पोर्टेबिलिटी समस्या है।


आपको अपने प्रश्न को नए StackOverflow प्रश्न के रूप में पूछना चाहिए, न कि आपके उत्तर के भाग के रूप में।
vog

OSX / Oracle java8 पर दो और चार के साथ काम करता है। लगता है कि आपके मूल जावा पर्यावरण (जिसे आप प्रकृति का उल्लेख नहीं करते हैं) के साथ एक समस्या है
TheMadsen
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.