Запуск сценария оболочки из java и получение возвращаемого значения

#java

#java

Вопрос:

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

Java-код 1:

 try {
            

    ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", "dir //pathOfSHFile//Test.sh");
                Process proc = processBuilder.start();
                proc.waitFor();
                BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
                String line = "";
                String output = "";
                while ((line = in.readLine()) != null)
                {
                 output  = line;
                } 
                System.out.println("### "   output);
            } catch (Throwable t) {
                t.printStackTrace();
            }
 

Test.sh файл

 #!/bin/sh
echo "good"
 

Вывод 1:

 ###  Volume in drive C is OSDisk Volume Serial Number is *** Directory of C:DataCode07-12-2020  12:10                22 Test.sh 
 

Ожидал «good» в качестве результата.

Java-код 2:

 try {
            Runtime rt = Runtime.getRuntime();
            Process pr = rt.exec(new String[]{"C:\Data\Code", ".\Test.sh"});

            BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            String line = "";
            while ((line = input.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
 

Вывод 2:

 java.io.IOException: Cannot run program "C:DataCode": CreateProcess error=5, Access is denied
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at java.lang.Runtime.exec(Runtime.java:621)
    at java.lang.Runtime.exec(Runtime.java:486)
    at Intersecttion.main(Intersecttion.java:53)
Caused by: java.io.IOException: CreateProcess error=5, Access is denied
    at java.lang.ProcessImpl.create(Native Method)
    at java.lang.ProcessImpl.<init>(ProcessImpl.java:444)
    at java.lang.ProcessImpl.start(ProcessImpl.java:140)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 3 more
 

Я пытался дать разрешение всем папкам, но результат все тот же.
Мне нужно также передать один аргумент сценарию, но я не уверен, как это сделать, а также запустить скрипт и получить значение выхода.
Есть ли лучший способ сделать это, кроме вышеперечисленных.

Комментарии:

1. Я действительно не помню, как именно это работает в Windows, но разве вы не должны запускать скрипт-бегун, например [ cmd.exe , /c , путь к исполняемому файлу script runner , путь к скрипту ]? (Я имею в виду, что нет аргументов с пробелами, нет пробелов между ними, как в вашем # 1, dir встроен в cmd, Windows не знает об ошибках, C:DataCode может быть каталогом и т. Д. И т. Д. И т. Д.)

2. Да, я пытался протестировать и запустить это в Windows. Я пытаюсь поместить код в Linux и проверить, работает он или нет

3. Нет, это то, чего мне не хватало, и я думаю, что в первом выводе он просто возвращал последнюю папку, которую я упомянул, вместо запуска Test.sh досье.

4. В Java 7 добавлен метод redirectOutput для класса ProcessBuilder . Существует также метод redirectError . Разве это не то, что вы ищете? или, возможно, метод inheritIO подходит?

Ответ №1:

Версия 2 пытается выполнить папку. Это должно сработать:

         String path = "C:\Data\Code";
        String command = path   "\Test.bat"; // Test.sh renamed
//      String command = "bash Test.sh"; // bash execution when installed on Windows
        
        Runtime rt = Runtime.getRuntime();
        
        Process pr = rt.exec(command, null, new File(path));

        BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line = "";
        while ((line = input.readLine()) != null) {
            System.out.println(line);
        }
 

Однако вместо этого вам, возможно, придется изменить свой сценарий на командный файл «Test.bat», поскольку Windows не будет изначально выполнять сценарии оболочки. Вы также можете установить bash и выполнить bash команду со сценарием в качестве параметра. Я добавил это как прокомментированную строку.

Комментарии:

1. OP запрашивает проблему выполнения сценария оболочки Unix (-like), а не пакетный файл Windows. Переименование файла сценария определенно не является решением, поскольку для этого требуется перенос сценария в Windows.

2. Где вы прочитали, что он должен быть Unix-подобным? echo «good» также может быть частью пакетного файла. Проблема, которую я понял здесь, заключалась в том, что все, что должно было быть выполнено, не было выполнено должным образом из Java.

3. 1) В названии вопроса четко указан сценарий «оболочки», в то время как Windows использует терминологию «пакетный файл» со времен DOS. 2) Фрагмент кода демонстрирует исходный код сценария оболочки. 3) Оба фрагмента Java пытаются выполнить test.sh . 4) Я не думаю, что у OP возникнет вопрос только о echo внешнем запуске сингла.

4. Тем не менее, я думаю, что проблема, отображаемая в обеих версиях выше, была вызвана не выполнением сценария оболочки, а выполнением команды в неправильном месте.

5. Я сейчас не на компьютере с Windows, но что произойдет, если не переименовывать файл, а bash установить его в Windows? Будет ли Windows связывать расширение sh файла с bash таким, чтобы оно выполняло эту работу?