¿Es posible escribir un solo archivo de script que se ejecute tanto en Windows (tratado como .bat) como en Linux (a través de Bash)?
Conozco la sintaxis básica de ambos, pero no me di cuenta. Probablemente podría explotar la sintaxis oscura de Bash o alguna falla del procesador por lotes de Windows.
El comando a ejecutar puede ser solo una línea para ejecutar otro script.
La motivación es tener un solo comando de arranque de la aplicación tanto para Windows como para Linux.
Actualización: La necesidad del script de shell "nativo" del sistema es que debe elegir la versión del intérprete correcta, ajustarse a ciertas variables de entorno conocidas, etc. No es preferible instalar entornos adicionales como CygWin; me gustaría mantener el concepto " descargar y ejecutar ".
El único otro lenguaje a considerar para Windows es Windows Scripting Host - WSH, que está preestablecido de forma predeterminada desde 98.
fuente
cp
integrados, o viceversa, por lo que escribir dos scripts separados puede ser pedagógicamente mejor que las técnicas avanzadas que se muestran aquí.Respuestas:
Lo que he hecho es usar la sintaxis de la etiqueta de cmd como marcador de comentarios . El carácter de etiqueta, dos puntos (
:
), es equivalente atrue
en la mayoría de shells POSIXish. Si sigue inmediatamente el carácter de la etiqueta por otro carácter que no se puede usar en aGOTO
, comentar sucmd
secuencia de comandos no debería afectar sucmd
código.El truco consiste en poner líneas de código después de la secuencia de caracteres “
:;
”. Si está escribiendo principalmente scripts de una sola línea o, como puede ser el caso, puede escribir una línea desh
para muchas líneas decmd
, lo siguiente podría estar bien. No olvide que cualquier uso de$?
debe estar antes de los siguientes dos puntos:
porque se:
restablece$?
a 0.Un ejemplo muy elaborado de protección
$?
:Otra idea para saltarse el
cmd
código es usar heredocs para quesh
trate elcmd
código como una cadena no utilizada y locmd
interprete. En este caso, nos aseguramos de que el delimitador de heredoc esté entre comillas (para evitarsh
hacer cualquier tipo de interpretación de su contenido cuando se ejecuta consh
) y comience con:
para que locmd
salte como cualquier otra línea que comience con:
.Según sus necesidades o estilo de codificación, el entrelazado
cmd
y elsh
código pueden tener sentido o no. El uso de heredocs es un método para realizar dicho entrelazado. Sin embargo, esto podría ampliarse con laGOTO
técnica :Los comentarios universales, por supuesto, se pueden hacer con la secuencia de caracteres
: #
o:;#
. El espacio o el punto y coma son necesarios porque sesh
considera#
parte del nombre de un comando si no es el primer carácter de un identificador. Por ejemplo, es posible que desee escribir comentarios universales en las primeras líneas de su archivo antes de usar elGOTO
método para dividir su código. Luego, puede informar a su lector de por qué su guión está escrito de manera tan extraña:Por lo tanto, algunas ideas y formas de lograr
sh
ycmd
scripts compatibles sin efectos secundarios graves que yo sepa (y sin tenercmd
salida'#' is not recognized as an internal or external command, operable program or batch file.
).fuente
.cmd
extensión, de lo contrario no se ejecutará en Windows. ¿Hay algún trabajo alrededor?.cmd
y marcarlos como ejecutables. De esa manera, la ejecución del script desde el shell predeterminado en Windows o Unix funcionará (solo se probó con bash). Debido a que no puedo pensar en una forma de incluir un shebang sin hacer que cmd se queje en voz alta, siempre debe invocar el script a través de shell. Es decir, asegúrese de usarexeclp()
oexecvp()
(creo quesystem()
es la forma "correcta" para usted) en lugar deexecl()
oexecv()
(estas últimas funciones solo funcionarán en scripts con shebangs porque van más directamente al sistema operativo).<Exec/>
MSBuild Task ) en lugar de como archivos por lotes independientes. Tal vez si tengo algo de tiempo en el futuro actualizaré la respuesta con la información en estos comentarios…puedes probar esto:
Probablemente necesitará usar
/r/n
como una nueva línea en lugar de un estilo Unix.Si recuerdo correctamente, los scripts no interpretan la nueva línea.bat
Unix como una nueva línea.Otra forma es crear un#.exe
archivo en la ruta que no hace nada en de manera similar a mi respuesta aquí: ¿Es posible incrustar y ejecutar VBScript dentro de un archivo por lotes sin usar un archivo temporal?EDITAR
La respuesta del binki es casi perfecta pero aún se puede mejorar:
Vuelve a utilizar el
:
truco y el comentario de varias líneas. Parece que cmd.exe (al menos en Windows10) funciona sin problemas con las EOL de estilo Unix, así que asegúrese de que su script se convierta en formato Linux. (El mismo enfoque se ha visto utilizado antes aquí y aquí ). Aunque usar shebang todavía producirá una salida redundante ...fuente
/r/n
al final de las líneas causará muchos dolores de cabeza en el script bash a menos que termine cada línea con un#
(ie#/r/n
); de esa manera\r
, se tratará como parte del comentario y se ignorará.# 2>NUL & ECHO Welcome to %COMSPEC%.
logra ocultar el error sobre el#
comando que no encuentracmd
. Esta técnica es útil cuando necesita escribir una línea independiente que solo será ejecutada porcmd
( por ejemplo, en aMakefile
).Quería comentar, pero solo puedo agregar una respuesta por el momento.
Las técnicas dadas son excelentes y las uso también.
Es difícil retener un archivo que tiene dos tipos de saltos de línea dentro, el
/n
de la parte bash y/r/n
la parte de Windows. La mayoría de los editores intentan hacer cumplir un esquema de salto de línea común adivinando qué tipo de archivo está editando. Además, la mayoría de los métodos para transferir el archivo a través de Internet (especialmente como un archivo de texto o script) blanquearán los saltos de línea, por lo que podría comenzar con un tipo de salto de línea y terminar con el otro. Si hizo suposiciones sobre los saltos de línea y luego le dio su script a otra persona para que lo usara, es posible que descubra que no funciona para ellos.El otro problema son los sistemas de archivos (o CD) montados en red que se comparten entre diferentes tipos de sistemas (especialmente cuando no se puede controlar el software disponible para el usuario).
Por lo tanto, uno debe usar el salto de línea de DOS
/r/n
y también proteger el script bash del DOS/r
poniendo un comentario al final de cada línea (#
). Tampoco puede usar continuaciones de línea en bash porque/r
hará que se rompan.De esta manera, quien use el script, y en cualquier entorno, funcionará.
¡Utilizo este método junto con la creación de Makefiles portátiles!
fuente
Lo siguiente funciona para mí sin errores o mensajes de error con Bash 4 y Windows 10, a diferencia de las respuestas anteriores. Llamo al archivo "lo que sea.cmd", lo hago
chmod +x
para que sea ejecutable en Linux, y lo hago con terminaciones de línea Unix (dos2unix
) para mantener a bash en silencio.fuente
Puedes compartir variables:
fuente
Hay varias formas de ejecutar diferentes comandos en
bash
ycmd
con el mismo script.cmd
ignorará las líneas que comienzan con:;
, como se menciona en otras respuestas. También ignorará la siguiente línea si la línea actual termina con el comandorem ^
, ya que el^
personaje escapará del salto de línea y la siguiente línea será tratada como un comentario porrem
.En cuanto a hacer
bash
ignorar lascmd
líneas, hay varias formas. He enumerado algunas formas de hacerlo sin romper loscmd
comandos:#
Comando inexistente (no recomendado)Si no hay ningún
#
comando disponiblecmd
cuando se ejecuta el script, podemos hacer esto:El
#
carácter al principio de lacmd
línea hacebash
que trate esa línea como un comentario.El
#
carácter al final de labash
línea se usa para comentar el\r
personaje, como señaló Brian Tompsett en su respuesta . Sin esto,bash
arrojará un error si el archivo tiene\r\n
finales de línea, requeridos porcmd
.Haciendo
# 2>nul
, estamos engañandocmd
para ignorar el error de algún#
comando inexistente , mientras seguimos ejecutando el comando que sigue.No use esta solución si hay un
#
comando disponible en elPATH
o si no tiene control sobre los comandos disponibles paracmd
.Usando
echo
para ignorar el#
personaje encmd
Podemos usar
echo
con su salida redirigida para insertarcmd
comandos enbash
el área comentada:Dado que el
#
carácter no tiene un significado especial encmd
, se trata como parte del texto paraecho
. Todo lo que teníamos que hacer era redirigir la salida delecho
comando e insertar otros comandos después.#.bat
Archivo vacíoLa
echo >/dev/null # 1>nul 2> #.bat
línea crea un#.bat
archivo vacío mientras está encendidocmd
(o reemplaza el existente#.bat
, si lo hay) y no hace nada mientras está encendidobash
.Este archivo será utilizado por la
cmd
(s) línea (s) que sigue incluso si hay alguna otra#
comando en elPATH
.El
del #.bat
comando en elcmd
código específico elimina el archivo que se creó. Solo tienes que hacer esto en la últimacmd
línea.No use esta solución si un
#.bat
archivo podría estar en su directorio de trabajo actual, ya que ese archivo se borrará.Recomendado: usar here-document para ignorar
cmd
comandos enbash
Al colocar el
^
carácter al final de lacmd
línea, nos escapamos del salto de línea, y al usar:
como delimitador del documento aquí, el contenido de la línea delimitador no tendrá ningún efecto sobrecmd
. De esa manera,cmd
solo ejecutará su línea después de:
línea haya terminado, teniendo el mismo comportamiento quebash
.Si desea tener varias líneas en ambas plataformas y solo ejecutarlas al final del bloque, puede hacer esto:
Siempre que no haya una
cmd
línea con exactamentehere-document delimiter
, esta solución debería funcionar. Puede cambiarhere-document delimiter
a cualquier otro texto.En todas las soluciones presentadas, los comandos solo se ejecutarán después de la última línea , lo que hace que su comportamiento sea consistente si hacen lo mismo en ambas plataformas.
Esas soluciones deben guardarse en archivos con
\r\n
saltos de línea, de lo contrario no funcionaráncmd
.fuente
Las respuestas anteriores parecen cubrir prácticamente todas las opciones y me ayudaron mucho. Incluyo esta respuesta aquí solo para demostrar el mecanismo que usé para incluir un script Bash y un script CMD de Windows en el mismo archivo.
LinuxWindowsScript.bat
Resumen
En Linux
La primera línea (
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
) será ignorada y el script fluirá a través de cada línea inmediatamente siguiente hasta queexit 0
se ejecute el comando. Una vez queexit 0
se alcanza, la ejecución del script terminará, ignorando los comandos de Windows debajo de él.En Windows
La primera línea ejecutará el
GOTO WINDOWS
comando, omitiendo los comandos de Linux inmediatamente posteriores y continuando la ejecución en la:WINDOWS
línea.Eliminación de devoluciones de carro en Windows
Como estaba editando este archivo en Windows, tuve que eliminar sistemáticamente los retornos de carro (\ r) de los comandos de Linux o, de lo contrario, obtuve resultados anormales al ejecutar la parte Bash. Para hacer esto, abrí el archivo en Notepad ++ e hice lo siguiente:
Activar la opción para la visualización de caracteres de fin de línea (
View
>Show Symbol
>Show End of Line
). Los retornos de carro se mostrarán comoCR
caracteres.Haga una búsqueda y reemplazo (
Search
>Replace...
) y marque laExtended (\n, \r, \t, \0, \x...)
opción.Escribe
\r
elFind what :
campo y en blanco elReplace with :
campo para que no haya nada en él.Comenzando en la parte superior del archivo, haga clic en el
Replace
botón hasta que todos losCR
caracteres de retorno de carro ( ) se hayan eliminado de la parte superior de Linux. Asegúrese de dejar losCR
caracteres de retorno de carro ( ) para la parte de Windows.El resultado debería ser que cada comando de Linux termina en solo un salto de línea (
LF
) y cada comando de Windows termina en un retorno de carro y un salto de línea (CR
LF
).fuente
Utilizo esta técnica para crear archivos jar ejecutables. Dado que el archivo jar / zip comienza en el encabezado zip, puedo poner un script universal para ejecutar este archivo en la parte superior:
@
in sh arroja un error que se canaliza/dev/null
y luego comienza un comentario. En cmd, la tubería/dev/null
falla porque el archivo no se reconoce en Windows, pero como Windows no detecta#
como comentario, se envía el errornul
. Luego hace un eco. Debido a que toda la línea está precedida por un@
, no se imprime en cmd.::
, que inicia un comentario en cmd, a noop en sh. Esto tiene la ventaja de que::
no se restablece$?
a0
. Utiliza el:;
truco " es una etiqueta".::
y se ignoran en cmd:: exit
el script sh termina y puedo escribir comandos cmdcommand not found
. Tienes que decidir tú mismo si lo necesitas o no.fuente
Necesitaba esto para algunos de mis scripts de instalación de paquetes de Python. La mayoría de las cosas entre el archivo sh y bat son iguales, pero pocas cosas como el manejo de errores son diferentes. Una forma de hacerlo es la siguiente:
Luego llamas a esto desde el script bash:
El archivo por lotes de Windows se ve así:
fuente
Pruebe mi proyecto BashWin en https://github.com/skanga/bashwin que usa BusyBox para la mayoría de los comandos de Unix
fuente
Existe una plataforma de herramientas de compilación independiente como Ant o Maven con sintaxis xml (basada en Java). Por lo tanto, puede reescribir todos sus scripts en Ant o Maven y ejecutarlos a pesar del tipo de sistema operativo. O simplemente puede crear un script de contenedor Ant, que analizará el tipo de sistema operativo y ejecutará el script bat o bash apropiado.
fuente