Как запустить скрипт оболочки Unix из кода Java? - PullRequest
143 голосов
/ 08 февраля 2009

Запустить команду Unix из Java довольно просто.

Runtime.getRuntime().exec(myCommand);

Но возможно ли запустить сценарий оболочки Unix из кода Java? Если да, будет ли хорошей практикой запускать сценарий оболочки из кода Java?

Ответы [ 17 ]

171 голосов
/ 08 февраля 2009

Вам действительно стоит взглянуть на 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();
23 голосов
/ 08 февраля 2009

Я бы сказал, что не в духе Java запускать скрипт оболочки из Java. Java должен быть кроссплатформенным, и запуск сценария оболочки ограничит его использование только UNIX.

С учетом вышесказанного определенно можно запускать сценарий оболочки из Java. Вы использовали бы точно такой же синтаксис, который вы перечислили (я сам не пробовал, но попробуйте выполнить скрипт оболочки напрямую, и если это не сработает, запустите саму оболочку, передав скрипт в качестве параметра командной строки) .

21 голосов
/ 08 февраля 2009

Я думаю, что вы ответили на свой вопрос с

Runtime.getRuntime().exec(myShellScript);

Относительно того, является ли это хорошей практикой ... что вы пытаетесь сделать с помощью сценария оболочки, который вы не можете сделать с Java?

20 голосов
/ 15 февраля 2014

Вы также можете использовать Apache Commons exec library также.

Пример:

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 .

11 голосов
/ 04 марта 2013

Да, это возможно. Это сработало для меня.

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());
        }
    }
4 голосов
/ 27 июля 2016

Вот мой пример. Надеюсь, что это имеет смысл.

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(this.isLinux()){
        Runtime.getRuntime().exec(new String[] {"/bin/sh", "-c", filePath}, null);
    }else if(this.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;
}
3 голосов
/ 19 ноября 2016

Чтобы избежать жесткого кодирования абсолютного пути, вы можете использовать следующий метод, который найдет и выполнит ваш скрипт, если он находится в корневом каталоге.

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 голосов
/ 14 октября 2016

Да, это возможно, и вы ответили на это! Что касается хороших практик, я думаю, что лучше запускать команды из файлов, а не прямо из вашего кода. Поэтому вы должны заставить Java выполнять список команд (или одну команду) в существующих файлах .bat, .sh, .ksh ... Вот пример выполнения списка команд в файле «MyFile.sh»:

    String[] cmd = { "sh", "MyFile.sh", "\pathOfTheFile"};
    Runtime.getRuntime().exec(cmd);
3 голосов
/ 30 июля 2016

Библиотека ZT Process Executor является альтернативой Apache Commons Exec. Он имеет функции для запуска команд, захвата их вывода, установки таймаутов и т. Д.

Я еще не использовал его, но он выглядит достаточно хорошо документированным.

Пример из документации: Выполнение команды, откачка stderr в логгер, возвращение вывода в виде строки UTF8.

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

В его документации перечислены следующие преимущества по сравнению с Commons Exec:

  • Улучшена обработка потоков
    • Чтение / запись в потоки
    • Перенаправление stderr на стандартный вывод
  • Улучшена обработка тайм-аутов
  • Улучшена проверка кодов выхода
  • Улучшенный API
    • Один вкладыш для довольно сложных случаев использования
    • Один лайнер для получения вывода процесса в строку
    • Доступ к объекту Process доступен
    • Поддержка асинхронных процессов ( Future )
  • Улучшено ведение журнала с SLF4J API
  • Поддержка нескольких процессов
2 голосов
/ 25 октября 2018

Ниже приведен пример запуска сценария Unix bash или Windows bat / cmd из Java. Аргументы могут быть переданы в сценарий и выведены из сценария. Метод принимает произвольное количество аргументов.

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 - это пример скрипта 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 - это простой сценарий Windows cmd 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...