web-dev-qa-db-fra.com

Comment exécuter un script shell Unix à partir de code Java?

C'est assez simple d'exécuter une commande Unix à partir de Java. 

Runtime.getRuntime().exec(myCommand);

Mais est-il possible d'exécuter un script Shell Unix à partir de code Java? Si tel est le cas, serait-il utile d’exécuter un script Shell à partir de code Java?

139
Vicky

Vous devriez vraiment regarder Process Builder . C'est vraiment construit pour ce genre de chose.

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

Je dirais que ce n’est pas dans l’esprit de Java d’exécuter un script Shell à partir de Java. Java est conçu pour être multi-plateforme, et exécuter un script Shell limiterait son utilisation à seulement UNIX.

Cela dit, il est certainement possible d’exécuter un script Shell à partir de Java. Vous utiliseriez exactement la même syntaxe que celle que vous avez indiquée (je ne l’ai pas essayé moi-même, mais essayez d’exécuter le script Shell directement, et si cela ne fonctionne pas, exécutez le Shell lui-même, en le passant comme paramètre de ligne de commande). .

23
Jack Leow

Je pense que vous avez répondu à votre propre question avec

Runtime.getRuntime().exec(myShellScript);

Quant à savoir s’il s’agit d’une bonne pratique ... qu’essayez-vous de faire avec un script Shell que vous ne pouvez pas faire avec Java?

21
Chris Ballance

Vous pouvez utiliser Apache Commons exec library aussi.

Exemple :

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

Pour référence ultérieure, un exemple est donné sur Apache Doc aussi.

20
Not a bug

Oui, il est possible de le faire. Cela a fonctionné pour moi.

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

Voici mon exemple. J'espère que cela a du sens.

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;
}
4
Lionel Yan

La bibliothèque ZT Process Executor est une alternative à Apache Commons Exec. Il a des fonctionnalités pour exécuter des commandes, capturer leur sortie, définir des délais, etc.

Je ne l'ai pas encore utilisé, mais il semble assez bien documenté.

Un exemple tiré de la documentation: Exécution d’une commande, pompage du stderr dans un enregistreur, renvoi du résultat sous forme de chaîne UTF8.

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

Sa documentation répertorie les avantages suivants par rapport à Commons Exec:

  • Amélioration de la gestion des flux
    • Lecture/écriture dans les flux
    • Redirection de stderr vers stdout
  • Amélioration de la gestion des délais
  • Vérification améliorée des codes de sortie
  • API améliorée
    • Une doublure pour des cas d'utilisation assez complexes
    • Une doublure pour obtenir la sortie du processus dans une chaîne
    • Accès à l'objet Process disponible
    • Prise en charge des processus asynchrones (Future
  • Enregistrement amélioré avec API SLF4J
  • Prise en charge de plusieurs processus
3
Lii

Oui, c'est possible et vous y avez répondu! En ce qui concerne les bonnes pratiques, je pense qu’il est préférable de lancer des commandes à partir de fichiers et non directement à partir de votre code. Il faut donc que Java exécute la liste des commandes (ou une commande) dans un fichier .bat, .sh, .ksh ... existant. Voici un exemple d’exécution d’une liste de commandes dans un fichier "MyFile.sh":

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

Pour éviter de coder en dur un chemin absolu, vous pouvez utiliser la méthode suivante pour rechercher et exécuter votre script s'il se trouve dans votre répertoire racine.

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

Quant à moi, tout doit être simple. Pour l'exécution du script, il suffit d'exécuter

new ProcessBuilder("pathToYourShellScript").start();
2
Vladimir Bosyi

C'est possible, exécutez-le comme n'importe quel autre programme. Assurez-vous simplement que votre script a le bon numéro! (she-bang) ligne en tant que première ligne du script et assurez-vous qu'il existe des autorisations d'exécution sur le fichier.

Par exemple, s'il s'agit d'un script bash, mettez #!/Bin/bash en haut du script, également chmod + x.

Aussi, si c'est une bonne pratique, non, surtout pas pour Java, mais si cela vous fait gagner beaucoup de temps à porter un script volumineux, et que vous ne recevez pas plus d'argent pour le faire;) économisez votre temps, exécutez la script et placez le portage vers Java sur votre liste de tâches à long terme.

1
Kekoa
  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

C'est une réponse tardive. Cependant, j'ai pensé mettre tout mon effort pour faire exécuter un script Shell à partir d'une application Spring-Boot destinée aux futurs développeurs. 

  1. Je travaillais dans Spring-Boot et je n’étais pas en mesure de trouver le fichier à exécuter à partir de mon application Java, qui lançait FileNotFoundFoundException. Je devais conserver le fichier dans le répertoire resources et définir le fichier à analyser dans pom.xml lors du démarrage de l'application, comme suit. 

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
                <include>**/*.sh</include>
            </includes>
        </resource>
    </resources>
    
  2. Après cela, j’avais des difficultés à exécuter le fichier et je retournais error code = 13, Permission Denied. Ensuite, je devais rendre le fichier exécutable en exécutant cette commande - chmod u+x myShellScript.sh 

Enfin, je pourrais exécuter le fichier en utilisant l'extrait de code suivant. 

public void runScript() {
    ProcessBuilder pb = new ProcessBuilder("src/main/resources/myFile.sh");
    try {
        Process p;
        p = pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

J'espère que cela résoudra le problème de quelqu'un. 

1
Reaz Murshed

Voici un exemple comment exécuter un script Unix bash ou Windows bat/cmd à partir de Java. Des arguments peuvent être passés sur le script et la sortie reçue du script. La méthode accepte un nombre arbitraire d'arguments.

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

Sous Unix/Linux, le chemin doit être de type Unix (avec/dans le séparateur). Sous Windows, utilisez '\'. Hier est un exemple de script bash (test.sh) qui reçoit un nombre arbitraire d'arguments et double chaque argument:

#!/bin/bash
counter=0
while [ $# -gt 0 ]
do
  echo argument $((counter +=1)): $1
  echo doubling argument $((counter)): $(($1+$1))
  shift
done

En appelant 

runScript("path_to_script/test.sh", "1", "2")

sous Unix/Linux, le résultat est:

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 est un script Windows cmd test.cmd simple qui compte le nombre d'arguments d'entrée:

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

Lors de l'appel du script sous Windows

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

La sortie est

Received from script: 3 arguments received
0

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

et pour l'usage;

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"});

OR

ShellAssistance.runShell("", "pg_dump", new String[]{"-U", "aliAdmin", "-f", "/home/Backup.sql", "StoresAssistanceDB"}, new Hashmap<>());
0
Ali Bagheri

La même chose que Solaris 5.10 fonctionne comme ceci ./batchstart.sh il y a une astuce que je ne sais pas si votre système d'exploitation l'accepte, utilisez plutôt \\. batchstart.sh. Cette double barre peut aider.

0
Saul

Je pense avec

System.getProperty("os.name"); 

Le fait de vérifier le système d’exploitation peut gérer le script Shell/bash s’ils sont pris en charge ... s'il est nécessaire de rendre le code portable.

0
DayaMoon