Runtime.exec () के साथ पाइप कैसे काम करें?


104

निम्नलिखित कोड पर विचार करें:

String commandf = "ls /etc | grep release";

try {

    // Execute the command and wait for it to complete
    Process child = Runtime.getRuntime().exec(commandf);
    child.waitFor();

    // Print the first 16 bytes of its output
    InputStream i = child.getInputStream();
    byte[] b = new byte[16];
    i.read(b, 0, b.length); 
    System.out.println(new String(b));

} catch (IOException e) {
    e.printStackTrace();
    System.exit(-1);
}

कार्यक्रम का आउटपुट है:

/etc:
adduser.co

जब मैं शेल से चलता हूं, तो निश्चित रूप से, यह उम्मीद के मुताबिक काम करता है:

poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release

प्रशिक्षु मुझे बताते हैं कि, इस तथ्य के कारण कि पाइप व्यवहार क्रॉस-प्लेटफ़ॉर्म नहीं है, जावा फैक्ट्री में काम करने वाले शानदार दिमाग, जावा को गारंटी नहीं दे सकते कि पाइप काम करते हैं।

मैं यह कैसे कर सकता हूँ?

मैं जावा निर्माण के बजाय अपने सभी पार्सिंग को करने जा रहा हूं grepऔर इसके बजाय sed, क्योंकि अगर मैं भाषा बदलना चाहता हूं, तो मुझे अपने पार्सिंग कोड को उस भाषा में फिर से लिखने के लिए मजबूर होना पड़ेगा, जो पूरी तरह से एक नहीं है।

शेल कमांड को कॉल करते समय मैं जावा को पाइपिंग और पुनर्निर्देशन कैसे कर सकता हूं?


मैं इसे इस तरह से देखता हूं: यदि आप इसे देशी जावा स्ट्रिंग हैंडलिंग के साथ करते हैं, तो आपको सभी प्लेटफार्मों के जावा समर्थन के लिए जावा ऐप की पोर्टेबिलिटी की गारंटी दी जाती है। OTOH, यदि आप इसे शेल कमांड्स के साथ करते हैं, तो जावा से लैंग गेज बदलना आसान है , लेकिन यह तभी काम करेगा जब आप पोसिक्स प्लेटफॉर्म पर हों। जिस प्लेटफॉर्म पर ऐप चलता है, उसके बजाय कुछ लोग ऐप लैंग्वेज बदल देते हैं। इसलिए मुझे लगता है कि आपका तर्क थोड़ा उत्सुक है।
Janus Troelsen

कुछ सरल के विशिष्ट मामले में जैसे कि command | grep fooआप commandजावा में मूल रूप से फ़िल्टरिंग कर रहे हैं। यह आपके कोड को कुछ अधिक जटिल बनाता है लेकिन आप समग्र संसाधन खपत और हमले की सतह को काफी कम कर देते हैं।
ट्रिपल

जवाबों:


182

एक स्क्रिप्ट लिखें, और अलग-अलग कमांड के बजाय स्क्रिप्ट निष्पादित करें।

पाइप शेल का एक हिस्सा है, इसलिए आप ऐसा कुछ भी कर सकते हैं:

String[] cmd = {
"/bin/sh",
"-c",
"ls /etc | grep release"
};

Process p = Runtime.getRuntime().exec(cmd);

@Kaj क्या होगा यदि आप के लिए विकल्प जोड़ना चाहते थे lsयानी ls -lrt?
kaustav datta

8
@ काज मैं देख रहा हूं कि आप शेल के लिए कमांड की एक स्ट्रिंग निर्दिष्ट करने के लिए -c का उपयोग करने की कोशिश कर रहे हैं, लेकिन मुझे समझ नहीं आता कि आपको केवल एक स्ट्रिंग के बजाय इसे एक स्ट्रिंग सरणी क्यों बनाना है?
डेविड डोरिया

2
अगर कोई androidयहां संस्करण की तलाश में है, तो /system/bin/shइसके बजाय का उपयोग करें
Nexen

25

मैं लिनक्स में एक समान समस्या में भाग गया, सिवाय इसके कि "ps -ef | grep someprocess"।
कम से कम "ls" के साथ आपके पास एक भाषा-स्वतंत्र (यद्यपि धीमी) जावा प्रतिस्थापन है। उदाहरण के लिए .:

File f = new File("C:\\");
String[] files = f.listFiles(new File("/home/tihamer"));
for (String file : files) {
    if (file.matches(.*some.*)) { System.out.println(file); }
}

"Ps" के साथ, यह थोड़ा कठिन है, क्योंकि Java में इसके लिए API नहीं है।

मैंने सुना है कि सिगर हमारी मदद करने में सक्षम हो सकता है: https://support.hyperic.com/display/SIGAR/Home

हालाँकि, सरलतम समाधान, (जैसा कि काज द्वारा बताया गया है) पाइप कमांड को एक स्ट्रिंग ऐरे के रूप में निष्पादित करना है। यहाँ पूर्ण कोड है:

try {
    String line;
    String[] cmd = { "/bin/sh", "-c", "ps -ef | grep export" };
    Process p = Runtime.getRuntime().exec(cmd);
    BufferedReader in =
            new BufferedReader(new InputStreamReader(p.getInputStream()));
    while ((line = in.readLine()) != null) {
        System.out.println(line); 
    }
    in.close();
} catch (Exception ex) {
    ex.printStackTrace();
}

क्यों स्ट्रिंग स्ट्रिंग पाइप के साथ काम करता है, जबकि एक भी स्ट्रिंग नहीं करता ... यह ब्रह्मांड के रहस्यों में से एक है (खासकर यदि आपने स्रोत कोड नहीं पढ़ा है)। मुझे संदेह है कि ऐसा इसलिए है क्योंकि जब निष्पादन को एक स्ट्रिंग दी जाती है, तो वह इसे पहले पार्स करता है (एक तरह से जिसे हम पसंद नहीं करते हैं)। इसके विपरीत, जब निष्पादन को एक स्ट्रिंग ऐरे दिया जाता है, तो यह इसे बिना पार्स किए ऑपरेटिंग सिस्टम पर भेज देता है।

दरअसल, अगर हम व्यस्त दिन से समय निकालकर सोर्स कोड ( http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14-java/lang/ पर देखें) Runtime.java # Runtime.exec% 28java.lang.String% 2Cjava.lang.String []% 2Cjava.io.File% 29 ), हम पाते हैं कि वास्तव में क्या हो रहा है।

public Process  [More ...] 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);
}

मैं उसी व्यवहार को पुनर्निर्देशित कर रहा हूं, अर्थात '>' वर्ण। स्ट्रिंग सरणियों पर यह अतिरिक्त विश्लेषण ज्ञानवर्धक है
क्राइस

आपको अपने व्यस्त कार्यक्रम में से एक दिन निकालने की ज़रूरत नहीं है - इसके बारे में आपकी आँखों के सामने लिखा है डॉक्स / एपि / जावा / लैंग /
रंटाइम.html

6

प्रत्येक प्रक्रिया को चलाने के लिए एक रनटाइम बनाएँ। पहले रनटाइम से आउटपुटस्ट्रीम को प्राप्त करें और दूसरे से इनपुटस्ट्रीम में कॉपी करें।


1
यह इंगित करने के लायक है कि यह ओएस-मूल पाइप की तुलना में बहुत कम कुशल है, क्योंकि आप मेमोरी को जावा प्रक्रिया के एड्रेस स्पेस में कॉपी कर रहे हैं और फिर बाद की प्रक्रिया के लिए वापस आ गए हैं।
टिम बुद्रेउ

0

@ काज स्वीकार जवाब लाइनक्स के लिए है। यह विंडोज के लिए बराबर है:

String[] cmd = {
"cmd",
"/C",
"dir /B | findstr /R /C:"release""
};
Process p = Runtime.getRuntime().exec(cmd);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.