Reto : escriba un único archivo de script foo.cmd
que se pueda invocar desde el cmd.exe
indicador de Windows (no PowerShell, no en modo administrador), para ejecutar código arbitrario específico de Windows ...
> .\foo.cmd
Hello Windows!
... pero también ser invocada inalterada desde una típica compatible con POSIX (Linux / OSX) Indicador Shell ( bash
, tcsh
o zsh
), para ejecutar código arbitrario POSIX-específica:
$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!
... sin necesidad de instalar o crear intérpretes / herramientas de terceros.
Sé que esto es posible, pero con cruft (es decir, en Windows, una o dos líneas de basura / mensaje de error se imprimen en stderr o stdout antes de "¡Hola Windows!").
El criterio ganador es la minimización de (primero) el número de líneas cruft y (segundo) el número de caracteres cruft.
Cruft se puede definir como cualquier salida de consola (stdout o stderr) que no se produce mediante el código de carga útil (arbitrario). Las líneas en blanco se cuentan en el recuento de líneas. Las líneas nuevas no se cuentan en el recuento de caracteres. Los puntajes crudos deben sumarse en ambas plataformas. Hagamos caso omiso de mecanismos como cls
ese barren la ruina pero a costa de eliminar también la salida de terminal anterior. Si Windows repite sus comandos porque aún no lo @echo off
ha activado , excluyamos los caracteres que gasta al imprimir el directorio actual y la solicitud.
Un criterio secundario es la simplicidad / elegancia de la solución interna foo.cmd
: si la "infraestructura" se define como cualquier carácter que no esté directamente involucrado en el código arbitrario de la carga útil, minimice primero el número de líneas que contienen caracteres de infraestructura, y segundo el número total de infraestructura caracteres.
¡Felicitaciones adicionales si la parte POSIX funcionará a pesar de que el archivo tenga finales de línea CRLF! (No estoy seguro de que la última parte sea posible).
Mi solución existente, que publicaré aquí una vez que otros hayan tenido la oportunidad, usa 6 líneas de código de infraestructura (52 caracteres excluyendo nuevas líneas). Produce 5 líneas de cruft, dos de las cuales están en blanco, todas las cuales ocurren en Windows (30 caracteres excluyendo nuevas líneas y excluyendo la cadena actual de directorio / solicitud que aparece en dos de esas líneas).
Respuestas:
0 líneas cruft, 0 caracteres cruft, 2 infra. líneas, 21 infra. caracteres, CRLF ok
Se eliminó la otra solución.
17 caracteres usando
exit /b
la respuesta de Digital Trauma:fuente
: command not found
cuando una línea en blanco se deslizaba en la carga útil posix, pero finalmente descubrí que no se trataba:
de la primera línea, sino más bien debido a los CRLF desprotegidos#
. Era una novedad para mí que#!
no se necesitaba una línea, que era responsable de dos de las líneas de Windows cruft en mi versión anterior.: ` >&3` \
a cada línea de la carga útil, supongo que se podría decir que su costo de infraestructura es arbitrariamente alto.#
necesaria la final ?Puntuación 0 cruft + 4 líneas infra + 32 caracteres infra. LF y CRLF OK.
Esto se basa en lo que encontré en este blog , con los bits de Amiga y otras líneas innecesarias eliminadas. Escondí las líneas de DOS en comillas comentadas en lugar de usar
\
líneas continuas, para que esto pueda funcionar tanto con CRLF como con LF.Con terminaciones de línea DOS CRLF o * nix LF, funciona en Ubuntu, OSX y wine:
Para crear esto exactamente (con CRLF) en una máquina * nix (incluido OSX), pegue lo siguiente en un terminal:
fuente
dosix
Es un buen nombre también. Pero en mi Mac (OS 10.9.4, Darwin Kernel Versión 13.3.0, GNU bash versión 3.2.51) no funciona con: ¿./dosix.cmd: line 13: syntax error: unexpected end of file
Alguna idea de por qué?Ya publicaré la solución que había estado usando, ya que ha sido superada. Es cortesía de un colega mío que creo que debe haber leído la misma entrada de blog que Digital Trauma .
#!
línea no le importa (por lo tanto, para intérpretes estándar comosh
y amigos, falla)fuente
#!
, lo que significa que la suya es la única respuesta hasta ahora para ser un script válido en un sistema POSIX. Seguro que algunos de los otros pueden ejecutarse si, pero solo si se inician desde un shell con una solución alternativa para scripts defectuosos.#!
línea faltante , pero usarán diferentes shells para interpretar el guión. Eso significa que un "script" que no comienza#!
tiene que ser válido no solo en un shell, sino en cada shell que pueda ser interpretado de manera plausible. Pero aún peor, solo funciona cuando se inicia desde otro shell. Tal secuencia de comandos puede funcionar desde la línea de comandos, pero no en el contexto donde finalmente tiene la intención de usarla.#!
línea en mi respuesta editada (1 línea de infraestructura con 21 caracteres) se puede combinar con la respuesta de cualquier otra persona a un costo de solo 2 líneas de Windows (de las cuales una está en blanco) o 23 caracteresResumen / síntesis de respuestas y discusión
Esto fue divertido y aprendí mucho.
Algunos cruft específicos de Windows son inevitables si, en su sistema POSIX, necesita comenzar su script con una
#!
línea. Si no tiene otra alternativa que hacer esto, entonces esta línea:es probablemente lo mejor que puede obtener. Hace que se genere una línea en blanco y una línea cruft en la consola de Windows. Sin embargo, es posible que pueda escapar sin un
#!
línea: en la mayoría de los sistemas, uno de los intérpretes de shell habituales terminará ejecutando el script (el problema es que no es universalmente predecible qué intérprete será; depende de, pero lo hará) no necesariamente ser idéntico al shell que usa para invocar el comando).Más allá de esa complicada primera línea, había algunas soluciones sin ingenio realmente ingeniosas. La presentación ganadora de jimmy23013 consistió en solo dos líneas cortas de infraestructura, e hizo uso del doble papel del
:
personaje para implementar una línea "silenciosa" en ambas plataformas (como un no-op de factosh
y amigos, y como una etiqueta marcador encmd.exe
):Que es posible hacer tales ejecutar un script en sistemas POSIX, incluso a pesar CRLF el fin de línea, pero para hacer esto para la mayoría de los intérpretes que tienen que terminar cada línea de su sección de POSIX (incluso líneas en blanco) con un carácter de comentario o comentario.
Finalmente, aquí hay dos variantes de una solución que he desarrollado en base a los aportes de todos. Pueden ser casi el mejor de todos los mundos, ya que minimizan el daño por la falta
#!
y hacen que la compatibilidad con CRLF sea aún más fluida. Se necesitan dos líneas de infraestructura adicionales. El shell POSIX impredecible solo debe interpretar una línea (estandarizada), y esa línea le permite seleccionar el shell para el resto del script (bash
en el siguiente ejemplo):Parte de la belleza de estas soluciones heredoc es que siguen siendo CRLF robustas: siempre que
<<:Z
llegue al final de la línea, el procesador heredoc realmente buscará y encontrará el token:Z\r
Como giro final, puede deshacerse de esos molestos comentarios de fin de línea y aún conservar la robustez de CRLF, quitando los
\r
caracteres antes de pasar las líneas al shell. Esto pone un poco más de fe en el shell impredecible (sería bueno usarlo en{ tr -d \\r|bash;}
lugar de,(tr -d \\r|bash)
pero los corchetes son una sintaxis de bash-only):Por supuesto, este enfoque sacrifica la capacidad de canalizar la entrada stdin en el script.
fuente