2012-01-09 13 views
11

Estoy buscando en una forma más eficiente para decidir:Java, Runtime.exec o ProcessBuilder: cómo saber si el archivo es shell o binario?

  • ¿Debo antepóngale la línea de comandos proporcionada por el usuario con el ejecutable de shell
  • En caso afirmativo, ¿cuál sería ese ejecutable? (/ bin/sh?/usr/bin/perl?/usr/bin/ksh? c: /../ cmd.exe?)

Se sabe que para iniciar un script de shell desde Java se debe se inicia la cáscara en su lugar:

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

Para iniciar un uno binario debe comenzar el binario en sí:

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

Si un binario se ejecuta con la cáscara, se produce un error:

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

Si un script se ejecuta sin la cáscara binaria, se produce un error:

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

Estoy en una situación en la que mi aplicación no sabe lo que se inicia, binario o un script.

La aplicación iniciada es un controlador de eventos proporcionado por el usuario final. Lo más probable es que sea un script de shell ejecutado bajo Unix; pero puede ser * .cmd en Windows, o un script Perl ejecutado bajo alguna plataforma oscura. Es Java, después de todo.

Mi primer intento ingenuo fue iniciar la línea de comandos con el shell, y ver si funciona. Si no, intente ejecutarlo como un binario.

Esto es feo y arriesgado: bajo una combinación desconocida de plataforma y shell el segundo ejecutado aún puede ejecutar el script, por segunda vez, con resultados impredecibles.

Además, no puedo decir cuándo la secuencia de comandos comenzó bien y falló debido a algún problema de cuando simplemente no puedo iniciarlo.

Lo mejor que estoy considerando ahora es:

  • leyó el guión y buscar los bytes no imprimible
  • Si lo encuentra, lo consideran un binario
  • Si no es así, añadir/bin/sh (o cmd.exe si está en Windows)

Indique si tiene alguna idea mejor en mente.

ACTUALIZACIÓN/solución parcial

Gracias a todos los que compartieron sus pensamientos conmigo.

Resulta que he confundido mí y para el resto de la Internet :)

No es necesario estar precedidos por se binarios antes de la línea de comandos introducidos por el usuario siempre que:

  1. el guión está en PATH
  2. (para Unix) el guión es ejecutable
  3. (para Unix) tiene la secuencia de comandos #!/ruta/a/intérprete

Mientras estaba probando mi código, una u otra de estas condiciones no cumplió. :-(

Después de realizar la prueba cuidadosamente el guión cero ha sido ejecutado.

El punto 3 se sólo se puede hacer por el usuario, y tienen que ser documentado en el Manual del usuario.

Debido a la forma en que estos scripts se propagan al sistema de destino, pueden no ser ejecutables y pueden no estar en PATH.

El único camino que me importa es uno relativo, por lo que es suficiente anteponer un ./ a cualquier ruta relativa

Making th Los scripts ejecutables bajo Unix (y cualquier otra plataforma) son un desafío mayor. No es WORA. Colocar/bin/sh delante de él puede ayudar, pero si recuerdo bien en Solaris, el shell no ejecutará un script no ejecutable.

Voy a publicar otra actualización más adelante esta semana.

+1

¿Su script de shell tiene una línea shebang apropiada ('#!') En la parte superior? Si es así, simplemente puede pedirle al núcleo que lo ejecute (siempre que sea el ejecutable '+ x') sin preocuparse por qué intérprete de comandos pueda necesitar. –

+0

No puedo saberlo. La secuencia de comandos proviene de usuarios finales que no se suministran con el software. –

Respuesta

2

Una posible solución es generar un script que envuelva el script/binario de ejecución desde su programa. De esa manera sabes que siempre es un guion. El script generado simplemente ejecuta el script/binario interno y devuelve el código de error (y posiblemente redirige la entrada/salida). Cuando termine, simplemente puede eliminarlo. Java le permite crear archivos temporales muy fácilmente.

3

Debería ser una bandera roja que debe pasar por estos aros solo para ejecutar un comando. Primero porque esto se está volviendo realmente complicado, y segundo porque Java fue diseñado para ser independiente de la plataforma. Cuando está investigando los hacks específicos del sistema operativo para que funcionen las clases integradas, debe dar un paso atrás y volver a examinar sus suposiciones.

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

en cuenta que el mensaje de error "archivo no encontrado", no "no se puede ejecutar script de shell" o algo por el error. La causa más probable de este error no es que estés ejecutando un script, sino que el script no se puede encontrar.

Si la secuencia de comandos está en el directorio actual, entonces necesita agregar un ./ en frente. Si no coloca una ruta explícita al ejecutable, entonces el ejecutable debe residir en uno de los directorios en su variable de entorno $PATH. El directorio actual . es generalmente no incluido en $PATH de forma predeterminada.

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

Si el nombre del script es un valor suministrado por el usuario entonces yo Levy este requisito en el usuario - se puede añadir el ./ para ellos, pero los programas UNIX general tratan de evitar ser demasiado útil. ¡Si olvidan poner ./, ese es su problema!

+0

Gracias por enjuagar mi cerebro. De hecho, ./script ayuda ... al menos parcialmente. –

0

En

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

pb ProcessBuilder = new ProcessBuilder ("/ bin/sh", "c", "/ ruta/binario", "arg1", "arg2); (sh: no pueda ejecutar el archivo binario)

una opción es aceptar la ruta de intérprete como otro argumento (probablemente a partir de una lista de valores conocidos) de los usuarios.

(Esto podría haber sido un comentario. no pude conseguir el formato derecha)

Cuestiones relacionadas