programing

Java 코드에서 Unix 쉘 스크립트를 실행하는 방법

newsource 2022. 8. 3. 23:18

Java 코드에서 Unix 쉘 스크립트를 실행하는 방법

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

Runtime.getRuntime().exec(myCommand);

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

프로세스 빌더를 살펴봐야 합니다.이건 정말 이런 종류의 것을 위해 만들어졌습니다.

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

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에도 예가 나와 있습니다.

제 생각에 당신은 당신 자신의 질문에 답한 것 같습니다.

Runtime.getRuntime().exec(myShellScript);

그것이 좋은 관행인지 아닌지에 대해서…자바에서는 할 수 없는 셸 스크립트로 무엇을 하려고 합니까?

자바에서 셸 스크립트를 실행하는 것은 자바 정신에 맞지 않는다고 생각합니다.Java는 크로스 플랫폼이어야 하며 셸 스크립트를 실행하면 UNIX로만 사용이 제한됩니다.

이와 같이 Java 내에서 셸 스크립트를 실행하는 것은 확실히 가능합니다.목록과 동일한 구문을 사용합니다(제가 직접 사용해 본 적은 없지만 셸 스크립트를 직접 실행해보고, 그래도 작동하지 않으면 셸 자체를 실행하여 스크립트를 명령줄 파라미터로 전달합니다).

네, 그렇게 하는 것은 가능합니다.나한테는 잘된 일이야.

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

여기 제 예가 있습니다.말이 됐으면 좋겠다.

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

합니다. 대답하다.코드에서 직접 를 실행하는 것이 아니라 파일에서 명령을 실행하는합니다.모범 사례에 대해서는 코드에서 직접 명령어를 실행하는 것이 아니라 파일에서 명령어를 실행하는 것이 좋다고 생각합니다. 기존 "Java"에 명령어 의 명령어..bat,.sh,.ksh...파일 에 제시하겠습니다.MyFile.sh:

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

절대 경로를 하드코드할 필요가 없도록 다음 방법을 사용하여 스크립트가 루트 디렉토리에 있는 경우 스크립트를 검색하여 실행할 수 있습니다.

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

나로서는 모든 것이 간단해야 한다.스크립트를 실행하려면 실행만 하면 됩니다.

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

ZT 프로세스 실행 프로그램 라이브러리는 Apache Commons Exec 대신 사용할 수 있습니다.명령어 실행, 출력 캡처, 타임아웃 설정 등이 가능합니다.

아직 써본 적은 없지만, 상당히 문서화되어 있는 것 같습니다.

문서의 예를 다음에 나타냅니다.명령어를 실행하여 stderr을 로거에 펌핑하고 출력을 UTF8 문자열로 반환합니다.

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

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

  • 스트림 처리 개선
    • 스트림 읽기/쓰기
    • stderr을 stdout으로 리다이렉트하는 중
  • 타임아웃 처리 개선
  • 종료 코드 확인 기능 향상
  • 【 】API
    • 매우 복잡한 사용 사례를 위한 하나의 라이너
    • 프로세스 출력을 문자열로 가져오기 위한 라이너 1개
    • Process 객체에 액세스할 수 있습니다.
    • 비동기 프로세스 지원(Future
  • SLF4J API를 통한 로깅 향상
  • 여러 프로세스 지원

다음으로 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);
    }
}

Unix/Linux에서 실행할 경우 경로는 Unix와 같아야 합니다(Windows에서 실행할 경우 '\'를 사용하십시오).Hier는 임의의 수의 인수를 수신하여 모든 인수를 2배로 하는 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")

Unix/Linux 의 출력은 다음과 같습니다.

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

이것은 답장이 늦다.그러나 향후 개발자를 위해 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();
    }
}

그게 누군가의 문제를 해결해 주길 바라.

가능합니다. 그냥 다른 프로그램과 같이 실행하세요.스크립트의 첫 번째 줄에 적절한 #!(she-bang) 행이 있는지 확인하고 파일에 실행 권한이 있는지 확인하십시오.

예를 들어 bash 스크립트가 #!/bin/bash를 스크립트 맨 위에 배치하는 경우 chmod +x도 입력합니다.

또, 좋은 프랙티스에 대해서는, 특히 Java에서는 그렇지 않습니다만, 큰 스크립트를 포팅하는 시간이 많이 절약되고, 게다가 추가의 보수를 받지 않는 경우).시간을 절약하고 스크립트를 실행해, Java로의 포팅을 장기 작업관리 리스트에 올립니다.

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

Solaris 5.10과 마찬가지로 다음과 같이 동작합니다../batchstart.shOS가 그 사용을 받아들일지 어떨지 모르는 트릭이 있습니다.\\. batchstart.sh대신.이 더블 슬래시가 도움이 될 거야

제 생각에는

System.getProperty("os.name"); 

에서 운영체제를 체크하면 셸/배시 스크리프가 지원되는 경우 관리할 수 있습니다.코드를 휴대할 필요가 있는 경우.

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

언급URL : https://stackoverflow.com/questions/525212/how-to-run-unix-shell-script-from-java-code