Java 코드에서 Unix 쉘 스크립트를 실행하는 방법은 무엇입니까?


155

Java에서 Unix 명령을 실행하는 것은 매우 간단합니다.

Runtime.getRuntime().exec(myCommand);

그러나 Java 코드에서 Unix 쉘 스크립트를 실행할 수 있습니까? 그렇다면 Java 코드 내에서 쉘 스크립트를 실행하는 것이 좋습니다.


3
해당 쉘 스크립트가 대화식이면 상황이 흥미로워집니다.
ernesto

그 문자열은 무엇입니까? 그렇다면, 작동하지 않습니다. exec 메소드에는 String [] 및 인수가 필요합니다. 내 answar 아래를 참조하십시오. 완벽하게 작동합니다.
Girdhar Singh Rathore

답변:


174

실제로 Process Builder를 살펴보십시오 . 실제로 이런 종류의 것을 위해 만들어졌습니다.

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에서 스크립트를 호출하는 것이 좋습니까? 성능 문제가 있습니까?
kautuksahni

1
Java 구성에 따라 스크립트를 실행하기 위해 / bin / bash 또는 sh 프로그램을 지정해야 할 수도 있습니다 ( stackoverflow.com/questions/25647806/… 참조 )
Ben Holland

@Milhous 나는 이것이 매우 늦었고 상황이 변경되었을 수 있음을 알고 있지만 현재 Java Process 문서에 따라 쉘 스크립트에 권장되는 방법은 아닙니다 : docs.oracle.com/javase/8/docs/api/java/lang/Process.html " 프로세스를 작성하는 방법은 기본 윈도우 프로세스, 데몬 프로세스, Microsoft Windows의 Win16 / DOS 프로세스 또는 쉘 스크립트와 같은 특정 기본 플랫폼의 특수 프로세스에 적합하지 않을 수 있습니다. "
Harman

24

Apache Commons exec 라이브러리 도 사용할 수 있습니다 .

예 :

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 에서도 예제를 제공합니다 .


Windows에서 이것을 실행할 수 있습니까?
bekur

@KisHanSarsecHaGajjar 또한 쉘 스크립트에서 출력을 캡처하여 java ui에 표시 할 수 있습니다. 나는 그것이 가능하다는 것을 알고 싶다
Kranthi Sama

@KranthiSama 당신은 설정할 수 있습니다 OutputStream에 대한 DefaultExecuter사용 DefaultExecuter.setStreamHandler에서 캡처 출력 방법 OutputStream. 자세한 내용은이 스레드를 참조하십시오 . 명령의 출력을 캡처하는 방법 ...
버그가 아닙니다.

1
링크는 프로젝트에 아파치 코 몬즈 Exec에서 라이브러리 종속성을 추가합니다 - commons.apache.org/proper/commons-exec/dependency-info.html
aunlead

2
최고의 솔루션.
Dev

23

Java 에서 쉘 스크립트를 실행하는 것이 Java의 정신에 있지 않다고 말하고 싶습니다 . Java는 크로스 플랫폼이어야하며 쉘 스크립트를 실행하면 사용이 UNIX로만 제한됩니다.

그렇게 말하면 Java 내에서 쉘 스크립트를 실행할 수 있습니다. 나열된 구문과 정확히 동일한 구문을 사용합니다 (내가 직접 시도하지는 않았지만 쉘 스크립트를 직접 실행 해보십시오. 그래도 작동하지 않으면 쉘 자체를 실행하고 스크립트를 명령 행 매개 변수로 전달하십시오) .


43
그렇습니다. 그러나 "자바의 정신"또는 "한 번에 쓸 수있는 쓰기"만트라는 여러 가지면에서 어쨌든 신화입니다.
BobbyShaftoe

15
그것에 대한 신화는 무엇입니까?
Chris Ballance

15
무엇에 대한 신화 것은 당신이 일반적으로 수많은 기록 끝날 것을,이다 switchesif자바 코어 라이브러리와 함께 제공되는 사람들의 최선의 노력에도 불구하고 서로 다른 플랫폼에서 동일 작동하지 않습니다 뉘앙스를 모두 해결하기 위해 문을.
브라이언 스위니

2
놀랍게도 충분히! 위의 모든 의견과 답변에 동의합니다!
AnBisw

11
@BobbyShaftoe 내가 16 년 동안 자바를 쓰고, 항상 창문에 개발되었다가, 내 모든 앱은 항상 솔라리스에 배포 / IBM이나 오라클은 유닉스 박스를 맛 나는 당신이 무엇에 관해 얘기하는지 아무 생각이 없다, 그래서
Kalpesh SONI을

21

나는 당신이 자신의 질문에 대답했다고 생각합니다.

Runtime.getRuntime().exec(myShellScript);

좋은 습관인지에 관해서는 Java로 할 수없는 쉘 스크립트로 무엇을하려고합니까?


Java 코드에서 특정 조건이 발생할 때 다른 서버에서 몇 개의 파일을 재 동기화 해야하는 비슷한 상황에 직면했습니다. 다른 더 좋은 방법이 있습니까?
v kumar

1
@Chris Ballance ... 나는이 의견이 거의 10 년 후라는 것을 알고있다. 특히 많은 이상한 채널과 상호 작용하는 프로젝트를 작업 할 때 :)
Stunner

Java에서 작업을 수행 할 다른 방법이없는 경우 기능을 쉘 스크립트로 푸시하는 것은 최후의 노력입니다. 쉘 스크립트로 작업을 진행하는 경우 상태와 종속성을 조정하는 것이 반드시 복잡합니다. 때때로, 쉘 스크립트가 유일한 방법이거나 타임 프레임이 약간의 작업을 수행 할 수있는 유일한 방법이기 때문에 이것이 그렇게하는 방법입니다.
Chris Ballance

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 프로세스 실행 프로그램 라이브러리는 아파치 코 몬즈 Exec에서의 대안입니다. 명령 실행, 출력 캡처, 시간 초과 설정 등의 기능이 있습니다.

아직 사용하지 않았지만 합리적으로 잘 정리되어 있습니다.

문서의 예 : 명령 실행, stderr를 로거로 펌핑하여 UTF8 문자열로 출력을 리턴합니다.

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

이 문서에는 Commons Exec에 비해 다음과 같은 장점이 있습니다.

  • 스트림 처리 개선
    • 스트림 읽기 / 쓰기
    • stderr를 stdout으로 리디렉션
  • 타임 아웃 처리 개선
  • 종료 코드 점검 개선
  • 개선 된 API
    • 매우 복잡한 사용 사례를위한 하나의 라이너
    • 프로세스 출력을 문자열로 얻는 하나의 라이너
    • 프로세스 에 대한 액세스사용 가능한 개체에
    • 비동기 프로세스 지원 ( Future )
  • 로 향상된 로깅 SLF4J API를 통한
  • 여러 프로세스 지원

2

다음은 Java에서 Unix bash 또는 Windows bat / cmd 스크립트를 실행하는 방법의 예입니다. 스크립트에서 인수를 전달하고 스크립트에서 출력을 수신 할 수 있습니다. 이 메소드는 임의의 수의 인수를 허용합니다.

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

유닉스 / 리눅스에서 실행할 때 경로는 유닉스와 같아야하며 ( '/'를 구분 기호로 사용) Windows에서 실행할 때는 '\'를 사용하십시오. Hier는 임의의 수의 인수를 받고 모든 인수를 두 배로 만드는 bash 스크립트 (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 Windows 스크립트 test.cmd로 여러 입력 인수를 계산합니다.

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

Windows에서 스크립트를 호출 할 때

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

출력은

Received from script: 3 arguments received

1

다른 프로그램처럼 실행할 수도 있습니다. 스크립트에 적절한 #이 있는지 확인하십시오! (she-bang) 행을 스크립트의 첫 번째 행으로 사용하고 파일에 대한 실행 권한이 있는지 확인하십시오.

예를 들어, bash 스크립트 인 경우 #! / bin / bash를 스크립트의 맨 위에두고 chmod + x도 입력하십시오.

또한 좋은 습관 인 경우, 특히 Java의 경우는 아니지만 큰 스크립트를 이식하는 데 많은 시간을 절약하고 추가 비용을 지불하지 않으면 시간을 절약하십시오.) 스크립트를 작성하고 장기적인 할 일 목록에 Java로 포팅하십시오.


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

이것은 늦은 답변입니다. 그러나 미래 개발자를 위해 Spring-Boot 응용 프로그램에서 쉘 스크립트를 실행하려면 많은 노력을 기울여야한다고 생각했습니다.

  1. 나는 Spring-Boot에서 일하고 있었고 Java 응용 프로그램에서 실행할 파일을 찾을 수 없어서 던졌습니다 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

솔라리스 5.10과 똑같은 일이 ./batchstart.sh당신의 OS가 그것을 \\. batchstart.sh대신 사용할 수 있는지 알지 못하는 트릭 이 있습니다 . 이 이중 슬래시가 도움이 될 수 있습니다.


0

나는 생각한다

System.getProperty("os.name"); 

운영 체제를 점검하면 쉘 / bash 스크립이 지원되는 경우이를 관리 할 수 ​​있습니다. 코드를 이식 가능하게 만들어야하는 경우.


0

리눅스 용

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<>());
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.