Запустити команду Unix з Java досить просто.
Runtime.getRuntime().exec(myCommand);
Але чи можна запустити скрипт оболонки Unix з коду Java? Якщо так, то чи було б гарною практикою запускати скрипт оболонки з коду Java?
Запустити команду Unix з Java досить просто.
Runtime.getRuntime().exec(myCommand);
Але чи можна запустити скрипт оболонки Unix з коду Java? Якщо так, то чи було б гарною практикою запускати скрипт оболонки з коду Java?
Відповіді:
Ви дійсно повинні подивитися на 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();
Ви також можете використовувати бібліотеку exec Apache Commons .
Приклад:
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 .
OutputStreamдля DefaultExecuterвикористання DefaultExecuter.setStreamHandlerметоди для виведення захоплення в OutputStream. Будь ласка, зверніться до цієї теми для отримання додаткової інформації: Як я можу отримати дані про команду ...
Я б сказав, що не в дусі Java запускати скрипт оболонки з Java. Java призначена для крос-платформи, а запуск сценарію оболонки обмежить її використання лише UNIX.
З огляду на це, безумовно, можна запустити скрипт оболонки з Java. Ви б використовували абсолютно той самий синтаксис, який ви вказали (я сам не пробував його, але спробуйте виконати скрипт оболонки безпосередньо, і якщо це не працює, виконайте оболонку, передавши скрипт у параметр командного рядка) .
switchesта ifзаяви, щоб обійти всі нюанси, які не працюють абсолютно однаково на різних платформах, незважаючи на зусилля людей, які придумали основні бібліотеки Java.
Я думаю, що ти відповів на власне запитання
Runtime.getRuntime().exec(myShellScript);
Щодо хорошої практики ... що ви намагаєтеся зробити зі скриптом оболонки, який ви не можете зробити з 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:
Ось приклад того, як запустити скрипт для bash Unix або 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 - це простий 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
Можна, просто виконайте це як будь-яку іншу програму. Просто переконайтеся, що ваш сценарій має належний номер #! (she-bang) рядок як перший рядок сценарію, і переконайтеся, що на файл є дозволи на виконання.
Наприклад, якщо це скрипт bash, поставте #! / Bin / bash у верхній частині сценарію, також chmod + x.
Крім того, якщо це хороша практика, ні, це не так, особливо для Java, але якщо це економить вам багато часу на перенесення великого сценарію, і ви не отримуєте додаткові гроші за це;) заощадите свій час, виконайте сценарій та перенесіть перенесення на Java у свій довгостроковий список todo.
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();
}
Це пізня відповідь. Однак я подумав про те, щоб укласти боротьбу, яку мені довелося перенести, щоб отримати сценарій оболонки, виконаний із програми Spring-Boot для майбутніх розробників.
Я працював у 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>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();
}
}
Сподіваюся, що вирішує чиюсь проблему.
для використання в 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<>());