जावा कोड से यूनिक्स शेल स्क्रिप्ट कैसे चलाएं?


155

जावा से यूनिक्स कमांड चलाना काफी सरल है।

Runtime.getRuntime().exec(myCommand);

लेकिन क्या जावा कोड से यूनिक्स शेल स्क्रिप्ट चलाना संभव है? यदि हाँ, तो क्या जावा कोड के भीतर से शेल स्क्रिप्ट चलाना एक अच्छा अभ्यास होगा?


3
यदि शेल स्क्रिप्ट इंटरैक्टिव है तो चीजें दिलचस्प हो जाती हैं।
एर्नेस्टो

MyCommand चर क्या है कि स्ट्रिंग? यदि हां, तो यह काम नहीं करेगा, निष्पादन विधि के लिए स्ट्रिंग [] और तर्क की आवश्यकता है, मेरे उत्तरदाता के नीचे देखें, यह पूरी तरह से काम करता है
गिरधर सिंह राठौर

जवाबों:


174

आपको वास्तव में प्रोसेस बिल्डर को देखना चाहिए । यह वास्तव में इस तरह की चीज के लिए बनाया गया है।

ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
 Map<String, String> env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory(new File("myDir"));
 Process p = pb.start();

3
क्या JAVA से स्क्रिप्ट बुलाना अच्छा है? किसी भी प्रदर्शन के मुद्दे?
कौतुकसहनी 5

1
ध्यान दें कि आपको जावा के कॉन्फ़िगरेशन के आधार पर स्क्रिप्ट को निष्पादित करने के लिए प्रोग्राम / बिन / बैश या श को निर्दिष्ट करने की आवश्यकता हो सकती है (देखें stackoverflow.com/questions/25647806/… )
बेन हॉलैंड

@ मुझे पता है कि यह काफी देर से है और चीजें बदल गई हैं, लेकिन वर्तमान जावा प्रोसेस प्रलेखन के अनुसार यह शेल स्क्रिप्ट के लिए अनुशंसित विधि नहीं है: docs.oracle.com/javase/8/docs/api/java/lang/Pro3.html " ऐसी प्रक्रियाएँ जो प्रक्रियाएँ बनाती हैं, कुछ विशेष प्लेटफ़ॉर्म पर विशेष प्रक्रियाओं के लिए अच्छी तरह से काम नहीं कर सकती हैं, जैसे कि देशी विंडो प्रक्रियाएँ, डेमॉन प्रक्रियाएँ, Microsoft Windows पर Win16 / DOS प्रक्रियाएँ या शेल स्क्रिप्ट। "
हरमन

24

आप अपाचे कॉमन्स निष्पादन पुस्तकालय का भी उपयोग कर सकते हैं ।

उदाहरण :

package testShellScript;

import java.io.IOException;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;

public class TestScript {
    int iExitValue;
    String sCommandString;

    public void runScript(String command){
        sCommandString = command;
        CommandLine oCmdLine = CommandLine.parse(sCommandString);
        DefaultExecutor oDefaultExecutor = new DefaultExecutor();
        oDefaultExecutor.setExitValue(0);
        try {
            iExitValue = oDefaultExecutor.execute(oCmdLine);
        } catch (ExecuteException e) {
            System.err.println("Execution failed.");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println("permission denied.");
            e.printStackTrace();
        }
    }

    public static void main(String args[]){
        TestScript testScript = new TestScript();
        testScript.runScript("sh /root/Desktop/testScript.sh");
    }
}

आगे के संदर्भ के लिए, Apache Doc पर भी एक उदाहरण दिया गया है ।


क्या मैं इसे विंडोज में चला सकता हूं?
बीकूर

@ KisHanSarsecHaGajjar हम शेलस्क्रिप्ट से आउटपुट को कैप्चर कर सकते हैं और इसे जावा यूआई में प्रदर्शित कर सकते हैं। मैं जानना चाहता हूं कि क्या ऐसा करना संभव है
क्रान्ति समा जूल

@KranthiSama आप आउटपुट को कैप्चर करने के लिए विधि का उपयोग करने के OutputStreamलिए सेट कर सकते हैं । कृपया इस धागे को अधिक जानकारी के लिए देखें: मैं एक कमांड के आउटपुट को कैसे पकड़ सकता हूं ...DefaultExecuterDefaultExecuter.setStreamHandlerOutputStream
बग

1
अपनी परियोजना के लिए अपाचे कॉमन्स
एक्सिक

2
सबसे अच्छा समाधान।
देव

23

मैं कहूंगा कि जावा से शेल स्क्रिप्ट चलाना जावा की भावना में नहीं है । जावा का मतलब क्रॉस प्लेटफॉर्म है, और एक शेल स्क्रिप्ट को चलाने से इसका उपयोग सिर्फ यूनिक्स तक सीमित हो जाएगा।

उस के साथ, यह निश्चित रूप से जावा के भीतर से एक खोल स्क्रिप्ट चलाने के लिए संभव है। आप अपने द्वारा सूचीबद्ध समान सिंटैक्स का उपयोग करेंगे (मैंने इसे स्वयं आज़माया नहीं है, लेकिन शेल स्क्रिप्ट को सीधे निष्पादित करने का प्रयास करें, और यदि वह काम नहीं करता है, तो शेल को निष्पादित करें, कमांड लाइन पैरामीटर के रूप में स्क्रिप्ट को पास करना) ।


43
हां, लेकिन कई मायनों में कि "जावा की भावना" या "हर जगह एक बार लिखें" मंत्र वैसे भी एक मिथक है।
BobbyShaftoe

15
इसके बारे में क्या पौराणिक है?
क्रिस बॉलेंस

15
इसके बारे में जो पौराणिक है, वह यह है कि आप आमतौर पर उन सभी बारीकियों के बारे में जानने के लिए कई switchesऔर ifबयानों को लिखते हैं जो जावा कोर पुस्तकालयों के साथ आए लोगों के सर्वोत्तम प्रयासों के बावजूद विभिन्न प्लेटफार्मों पर बिल्कुल समान नहीं हैं।
ब्रायन स्वीनी

2
अप्रत्याशित रूप से पर्याप्त! मैं उपरोक्त सभी टिप्पणियों और उत्तर से सहमत हूं!
AnBisw

11
@BobbySftftoe मैं 16 साल से जावा लिख ​​रहा हूं, और हमेशा विंडोज़ पर विकसित किया गया है, मेरे सभी ऐप हमेशा सोलारिस / ibm या ऑर्कल फ्लेवर यूनिक्स बॉक्स पर तैनात किए जाते हैं, इसलिए मुझे नहीं पता कि आप किस बारे में बात कर रहे हैं
कल्पेश सोनी

21

मुझे लगता है कि आपने अपने प्रश्न का उत्तर दिया है

Runtime.getRuntime().exec(myShellScript);

जैसे कि यह अच्छा अभ्यास है ... आप एक शेल स्क्रिप्ट के साथ क्या करने की कोशिश कर रहे हैं जो आप जावा के साथ नहीं कर सकते हैं?


मुझे एक समान स्थिति का सामना करना पड़ा है जहाँ मुझे अपने जावा कोड में एक निश्चित स्थिति होने पर विभिन्न सर्वरों पर कुछ फ़ाइलों को rsync करने की आवश्यकता होती है। क्या कोई और बेहतर तरीका है?
v कुमार

1
@ क्रिस बैलेंस ... मुझे पता है कि यह टिप्पणी लगभग 10 साल बाद है। खासकर जब आप एक ऐसे प्रोजेक्ट पर काम कर रहे हैं, जो इतने विषम चैनलों के साथ बातचीत करता है :)
स्टनरनर

यदि किसी अन्य तरीके से जावा में काम करने का कोई अन्य तरीका नहीं है, तो शेल स्क्रिप्ट की कार्यक्षमता को पुश करना एक अंतिम-खाई प्रयास होगा। यदि आप किसी कार्य को शेल स्क्रिप्ट से बाहर कर रहे हैं, तो यह आवश्यक रूप से राज्य और निर्भरता को समन्वित करने के लिए जटिल होगा। कभी-कभी, एक शेल स्क्रिप्ट एकमात्र तरीका या समय-सीमा है जो इसे थोड़ा सा काम पूरा करने का एकमात्र उचित तरीका बनाती है, इसलिए यह ऐसा करने का एक तरीका है।
क्रिस बालेंस

11

हां ऐसा करना संभव है। इसने मेरे लिए काम किया।

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.omg.CORBA.portable.InputStream;

public static void readBashScript() {
        try {
            Process proc = Runtime.getRuntime().exec("/home/destino/workspace/JavaProject/listing.sh /"); //Whatever you want to execute
            BufferedReader read = new BufferedReader(new InputStreamReader(
                    proc.getInputStream()));
            try {
                proc.waitFor();
            } catch (InterruptedException e) {
                System.out.println(e.getMessage());
            }
            while (read.ready()) {
                System.out.println(read.readLine());
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

7

यहाँ मेरा उदाहरण है। आशा है कि यह समझ में आता है।

public static void excuteCommand(String filePath) throws IOException{
    File file = new File(filePath);
    if(!file.isFile()){
        throw new IllegalArgumentException("The file " + filePath + " does not exist");
    }
    if(isLinux()){
        Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null);
    }else if(isWindows()){
        Runtime.getRuntime().exec("cmd /c start " + filePath);
    }
}
public static boolean isLinux(){
    String os = System.getProperty("os.name");  
    return os.toLowerCase().indexOf("linux") >= 0;
}

public static boolean isWindows(){
    String os = System.getProperty("os.name");
    return os.toLowerCase().indexOf("windows") >= 0;
}

5

हाँ, यह संभव है और आपने इसका उत्तर दिया है! अच्छी प्रथाओं के बारे में, मुझे लगता है कि फ़ाइलों से कमांड लॉन्च करना बेहतर है और सीधे आपके कोड से नहीं। आप बनाना है तो जावा में एक मौजूदा आदेश (या एक आदेश) की सूची पर अमल .bat, .sh, .ksh... फ़ाइलें। यहाँ एक फ़ाइल में आदेशों की सूची निष्पादित करने का एक उदाहरण है MyFile.sh:

    String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
    Runtime.getRuntime().exec(cmd);

4

एक निरपेक्ष पथ को हार्डकोड करने से बचने के लिए, आप निम्न विधि का उपयोग कर सकते हैं जो आपकी स्क्रिप्ट को ढूंढ और निष्पादित करेगा यदि यह आपकी रूट निर्देशिका में है।

public static void runScript() throws IOException, InterruptedException {
    ProcessBuilder processBuilder = new ProcessBuilder("./nameOfScript.sh");
    //Sets the source and destination for subprocess standard I/O to be the same as those of the current Java process.
    processBuilder.inheritIO();
    Process process = processBuilder.start();

    int exitValue = process.waitFor();
    if (exitValue != 0) {
        // check for errors
        new BufferedInputStream(process.getErrorStream());
        throw new RuntimeException("execution of script failed!");
    }
}

3

मेरे लिए सभी चीजें सरल होनी चाहिए। रनिंग स्क्रिप्ट के लिए बस अमल करने की जरूरत है

new ProcessBuilder("pathToYourShellScript").start();

3

ZT प्रक्रिया निर्वाहक लाइब्रेरी Apache कॉमन्स Exec के लिए एक विकल्प है। इसमें कमांड चलाने, उनके आउटपुट को कैप्चर करने, टाइमआउट सेट करने आदि की कार्यक्षमता है।

मैंने अभी तक इसका उपयोग नहीं किया है, लेकिन यह काफी अच्छी तरह से प्रलेखित है।

प्रलेखन से एक उदाहरण: कमांड को निष्पादित करना, एक लकड़हारे को stderr पंप करना, आउटपुट को UTF8 स्ट्रिंग के रूप में वापस करना।

 String output = new ProcessExecutor().command("java", "-version")
    .redirectError(Slf4jStream.of(getClass()).asInfo())
    .readOutput(true).execute()
    .outputUTF8();

इसका प्रलेखन कॉमन्स एक्सक पर निम्नलिखित लाभों को सूचीबद्ध करता है:

  • धाराओं का बेहतर संचालन
    • धाराओं को पढ़ना / लिखना
    • Stdout को stdout पर पुनर्निर्देशित करना
  • टाइमआउट की बेहतर हैंडलिंग
  • निकास कोड की बेहतर जाँच
  • उन्नत एपीआई
    • काफी जटिल उपयोग मामलों के लिए एक लाइनर
    • एक लाइनर एक स्ट्रिंग में प्रक्रिया उत्पादन प्राप्त करने के लिए
    • उपलब्ध प्रक्रिया ऑब्जेक्ट तक पहुँच
    • Async प्रक्रियाओं के लिए समर्थन ( भविष्य )
  • SLF4J API के साथ बेहतर लॉगिंग
  • कई प्रक्रियाओं के लिए समर्थन

2

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

public static void runScript(String path, String... args) {
    try {
        String[] cmd = new String[args.length + 1];
        cmd[0] = path;
        int count = 0;
        for (String s : args) {
            cmd[++count] = args[count - 1];
        }
        Process process = Runtime.getRuntime().exec(cmd);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try {
            process.waitFor();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        while (bufferedReader.ready()) {
            System.out.println("Received from script: " + bufferedReader.readLine());
        }
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
        System.exit(1);
    }
}

जब यूनिक्स / लिनक्स पर चल रहा हो, तो पथ को यूनिक्स की तरह ('/' सेपरेटर के रूप में) होना चाहिए, जब विंडोज पर चल रहा हो - '\' का उपयोग करें। हायर एक बैश स्क्रिप्ट (test.sh) का एक उदाहरण है जो मनमानी संख्या प्राप्त करता है और हर तर्क को दोगुना करता है:

#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
  echo argument $((counter +=1)): $1
  echo doubling argument $((counter)): $(($1+$1))
  shift
done

जब बुला रहे हो

runScript("path_to_script/test.sh", "1", "2")

यूनिक्स / लिनक्स पर, आउटपुट है:

Received from script: argument 1: 1
Received from script: doubling argument 1: 2
Received from script: argument 2: 2
Received from script: doubling argument 2: 4

Hier एक सरल cmd विंडोज स्क्रिप्ट test.cmd है जो इनपुट तर्कों की संख्या की गणना करता है:

@echo off
set a=0
for %%x in (%*) do Set /A a+=1 
echo %a% arguments received

विंडोज पर स्क्रिप्ट को कॉल करते समय

  runScript("path_to_script\\test.cmd", "1", "2", "3")

आउटपुट है

Received from script: 3 arguments received

1

यह संभव है, बस इसे किसी अन्य कार्यक्रम के रूप में निष्पादित करें। बस सुनिश्चित करें कि आपकी स्क्रिप्ट में उचित # है! (she-bang) लाइन स्क्रिप्ट की पहली लाइन के रूप में है, और सुनिश्चित करें कि फ़ाइल पर अनुमतियाँ निष्पादित हैं।

उदाहरण के लिए, यदि यह स्क्रिप्ट के शीर्ष पर एक बैश स्क्रिप्ट है #! / बिन / बैश, भी chmod + x।

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


1
  String scriptName = PATH+"/myScript.sh";
  String commands[] = new String[]{scriptName,"myArg1", "myArg2"};

  Runtime rt = Runtime.getRuntime();
  Process process = null;
  try{
      process = rt.exec(commands);
      process.waitFor();
  }catch(Exception e){
      e.printStackTrace();
  }  

1

यह एक देर से जवाब है। हालाँकि, मैंने सोचा था कि भविष्य के डेवलपर्स के लिए स्प्रिंग-बूट एप्लिकेशन से निष्पादित होने के लिए मुझे एक शेल स्क्रिप्ट प्राप्त करने के लिए संघर्ष करना होगा।

  1. मैं स्प्रिंग-बूट में काम कर रहा था और मुझे अपने जावा एप्लिकेशन से निष्पादित होने वाली फ़ाइल नहीं मिल रही थी और यह फेंक रहा था FileNotFoundFoundException। मुझे फ़ाइल को resourcesनिर्देशिका में रखना था और फ़ाइल को स्कैन करने के लिए सेट करना pom.xmlथा जबकि आवेदन निम्न की तरह शुरू किया जा रहा था।

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
                <include>**/*.sh</include>
            </includes>
        </resource>
    </resources>
  2. उसके बाद मुझे फ़ाइल को निष्पादित करने में समस्या हो रही थी और यह वापस आ रहा था error code = 13, Permission Denied। तब मुझे इस कमांड को चलाकर फाइल को निष्पादन योग्य बनाना था -chmod u+x myShellScript.sh

अंत में, मैं निम्नलिखित कोड स्निपेट का उपयोग करके फ़ाइल को निष्पादित कर सकता हूं।

public void runScript() {
    ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
    try {
        Process p;
        p = pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

आशा है कि किसी की समस्या को हल करता है।


0

बस एक ही बात है कि Solaris 5.10 यह इस तरह से काम करता ./batchstart.shहै एक चाल है मुझे पता नहीं है अगर आपका ओएस \\. batchstart.shइसके बजाय इसका उपयोग स्वीकार करता है । यह डबल स्लैश मदद कर सकता है।


0

मुझे लगता है

System.getProperty("os.name"); 

ऑपरेटिंग सिस्टम की जाँच करने पर शेल / बैश स्क्रिफ़ का प्रबंधन किया जा सकता है, यदि ऐसा समर्थित हो। यदि कोड को पोर्टेबल बनाने की आवश्यकता है।


0

linux के उपयोग के लिए

public static void runShell(String directory, String command, String[] args, Map<String, String> environment)
{
    try
    {
        if(directory.trim().equals(""))
            directory = "/";

        String[] cmd = new String[args.length + 1];
        cmd[0] = command;

        int count = 1;

        for(String s : args)
        {
            cmd[count] = s;
            count++;
        }

        ProcessBuilder pb = new ProcessBuilder(cmd);

        Map<String, String> env = pb.environment();

        for(String s : environment.keySet())
            env.put(s, environment.get(s));

        pb.directory(new File(directory));

        Process process = pb.start();

        BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

        int exitValue = process.waitFor();

        if(exitValue != 0) // has errors
        {
            while(errReader.ready())
            {
                LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
        else
        {
            while(inputReader.ready())
            {
                LogClass.log("Shell Result : " + inputReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
    }
    catch(Exception e)
    {
        LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
    }
}

public static void runShell(String path, String command, String[] args)
{
    try
    {
        String[] cmd = new String[args.length + 1];

        if(!path.trim().isEmpty())
            cmd[0] = path + "/" + command;
        else
            cmd[0] = command;

        int count = 1;

        for(String s : args)
        {
            cmd[count] = s;
            count++;
        }

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

        BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedWriter outputReader = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
        BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

        int exitValue = process.waitFor();

        if(exitValue != 0) // has errors
        {
            while(errReader.ready())
            {
                LogClass.log("ErrShell: " + errReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
        else
        {
            while(inputReader.ready())
            {
                LogClass.log("Shell Result: " + inputReader.readLine(), LogClass.LogMode.LogAll);
            }
        }
    }
    catch(Exception e)
    {
        LogClass.log("Err: RunShell, " + e.toString(), LogClass.LogMode.LogAll);
    }
}

और उपयोग के लिए;

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});

या

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.