Java, Runtime.exec ou ProcessBuilder: comment savoir si le fichier est shell ou binary?

Je cherche un moyen plus efficace de décider:

  • Dois-je préfixer la ligne de commande fournie par l’utilisateur avec l’exécutable shell
  • Si oui, quel serait cet exécutable? (/ bin / sh? / usr / bin / perl? / usr / bin / ksh? c: /../ cmd.exe?)

Il est connu que pour démarrer un script shell à partir de Java, il convient de démarrer le shell:

ProcessBuilder pb = new ProcessBuilder("/bin/sh", "script.sh", "arg1", "arg2); 

Pour démarrer un binary, il faut commencer par le binary lui-même:

 ProcessBuilder pb = new ProcessBuilder("/path/binary", "arg1", "arg2); 

Si un binary est exécuté avec shell, cela produit une erreur:

 ProcessBuilder pb = new ProcessBuilder("/bin/sh", "/path/binary", "arg1", "arg2); (sh: cannot execute binary file) 

Si un script shell est exécuté sans le binary shell, il génère une erreur:

 ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2); (error 2: file not found) 

Je suis dans une situation où mon application ne sait pas ce qu’elle démarre, que ce soit du binary ou un script.

L’application démarrée est un gestionnaire d’événements fourni par l’utilisateur final . Ce sera probablement un script shell exécuté sous Unix; mais il peut s’agir d’un fichier * .cmd sous Windows ou d’un script Perl exécuté sous une plate-forme obscure. C’est Java, après tout.

Ma première tentative naïve a été de démarrer la ligne de commande avec le shell et de voir si cela fonctionne. Sinon, essayez de l’exécuter en tant que binary.

C’est moche et risqué: sous une combinaison inconnue de plate-forme et de shell, le second utilisateur exécuté peut toujours exécuter le script une seconde fois, avec des résultats imprévisibles.

En outre, je ne peux pas dire quand le script a démarré correctement et a échoué en raison d’un problème qui lui est propre, car je ne peux tout simplement pas le démarrer.

La meilleure chose que je considère maintenant est:

  • Lisez le script et recherchez tous les octets non imprimables.
  • Si trouvé, considérez-le comme un binary
  • Sinon, ajoutez / bin / sh (ou cmd.exe sous Windows)

S’il vous plaît aviser si vous avez de meilleures idées en tête.

MISE À JOUR / SOLUTION PARTIELLE

Merci à tous ceux qui ont partagé leurs pensées avec moi.

Il se trouve que je me suis confondu avec le rest d’Internet 🙂

Il n’est pas nécessaire d’append le binary shall avant la ligne de commande entrée par l’utilisateur, à condition que:

  1. le script est dans PATH
  2. (pour Unix) le script est exécutable
  3. (pour Unix) le script a #! / path / to / interpreter

Pendant que je testais mon code, l’une ou l’autre de ces conditions ne s’est pas remplie. 🙁

Après avoir effectué le test avec soin, le script de travail a été exécuté.

Le point 3 est uniquement réalisable par l’utilisateur et doit être documenté dans le manuel de l’utilisateur.

En raison de la manière dont ces scripts sont propagés sur le système cible, ils peuvent ne pas être exécutables et ne pas figurer dans PATH.

Le seul chemin qui m’intéresse est le chemin relatif, il suffit donc d’append un ./ à un chemin relatif.

Rendre les scripts exécutables sous Unix (et sur toute autre plate-forme) constitue un défi supplémentaire. Ce n’est pas WORA. Placer / bin / sh devant peut aider, mais si je me souviens bien sous Solaris, le shell n’exécutera pas de script non exécutable.

Je posterai une autre mise à jour plus tard cette semaine.

Ce devrait être un drapeau rouge que vous devez sauter à travers ces cerceaux juste pour exécuter une commande. D’abord parce que cela devient vraiment compliqué, et ensuite parce que Java a été conçu pour être indépendant de la plate-forme. Lorsque vous étudiez des hacks spécifiques à un système d’exploitation pour que les classes intégrées fonctionnent, vous devez vous retirer et réexaminer vos hypothèses.

 ProcessBuilder pb = new ProcessBuilder("script.sh", "arg1", "arg2); (error 2: file not found) 

Notez que le message d’erreur est “fichier non trouvé”, pas “ne peut pas exécuter de script shell” ou une telle erreur. La cause la plus probable de cette erreur n’est pas le fait que vous exécutez un script, mais que le script est introuvable.

Si le script se trouve dans le répertoire actuel, vous devez append un ./ devant. Si vous ne définissez pas de chemin explicite vers l’exécutable, celui-ci doit résider dans l’un des répertoires de votre variable d’environnement $PATH . Le répertoire en cours . n’est généralement pas inclus dans $PATH par défaut.

 ProcessBuilder pb = new ProcessBuilder("./script.sh", "arg1", "arg2); 

Si le nom de script est une valeur fournie par l’utilisateur, je demanderais cette exigence à l’utilisateur. Vous pouvez append le ./ pour lui, mais les programmes UNIX tentent généralement d’éviter d’être trop utile. S’ils oublient de mettre ./ alors c’est leur problème!

Une solution possible consiste à générer un script qui enveloppe le script / le binary en cours d’exécution à partir de votre programme. De cette façon, vous savez que c’est toujours un script. Le script généré exécute simplement le script interne / binary et renvoie le code d’erreur (et redirige éventuellement les entrées / sorties). Lorsque vous avez terminé, vous pouvez simplement le supprimer. Java vous permet de créer très facilement des fichiers temporaires.

Sur

ProcessBuilder pb = nouveau ProcessBuilder (“/ bin / sh”, “/ chemin / binary”, “arg1”, “arg2); (sh: impossible d’exécuter le fichier binary)

ProcessBuilder pb = nouveau ProcessBuilder (“/ bin / sh”, “-c”, “/ chemin / binary”, “arg1”, “arg2); (sh: impossible d’exécuter le fichier binary)

Une option consiste à accepter le chemin de l’interpréteur en tant qu’autre argument (probablement tiré d’une liste de valeurs connues) des utilisateurs.

(Cela aurait pu être un commentaire. Je n’ai pas pu obtenir le bon formatage)