¿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

cpintegrados, 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 atrueen 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 sucmdsecuencia de comandos no debería afectar sucmdcó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 deshpara 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
cmdcódigo es usar heredocs para queshtrate elcmdcódigo como una cadena no utilizada y locmdinterprete. En este caso, nos aseguramos de que el delimitador de heredoc esté entre comillas (para evitarshhacer cualquier tipo de interpretación de su contenido cuando se ejecuta consh) y comience con:para que locmdsalte como cualquier otra línea que comience con:.Según sus necesidades o estilo de codificación, el entrelazado
cmdy elshcó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 laGOTOté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 seshconsidera#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 elGOTOmé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
shycmdscripts compatibles sin efectos secundarios graves que yo sepa (y sin tenercmdsalida'#' is not recognized as an internal or external command, operable program or batch file.).fuente
.cmdextensión, de lo contrario no se ejecutará en Windows. ¿Hay algún trabajo alrededor?.cmdy 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/ncomo una nueva línea en lugar de un estilo Unix.Si recuerdo correctamente, los scripts no interpretan la nueva línea.batUnix como una nueva línea.Otra forma es crear un#.exearchivo 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/nal 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
/nde la parte bash y/r/nla 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/ny también proteger el script bash del DOS/rponiendo un comentario al final de cada línea (#). Tampoco puede usar continuaciones de línea en bash porque/rhará 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 +xpara 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
bashycmdcon el mismo script.cmdignorará 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
bashignorar lascmdlíneas, hay varias formas. He enumerado algunas formas de hacerlo sin romper loscmdcomandos:#Comando inexistente (no recomendado)Si no hay ningún
#comando disponiblecmdcuando se ejecuta el script, podemos hacer esto:El
#carácter al principio de lacmdlínea hacebashque trate esa línea como un comentario.El
#carácter al final de labashlínea se usa para comentar el\rpersonaje, como señaló Brian Tompsett en su respuesta . Sin esto,basharrojará un error si el archivo tiene\r\nfinales de línea, requeridos porcmd.Haciendo
# 2>nul, estamos engañandocmdpara 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 elPATHo si no tiene control sobre los comandos disponibles paracmd.Usando
echopara ignorar el#personaje encmdPodemos usar
echocon su salida redirigida para insertarcmdcomandos enbashel á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 delechocomando e insertar otros comandos después.#.batArchivo vacíoLa
echo >/dev/null # 1>nul 2> #.batlínea crea un#.batarchivo 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 #.batcomando en elcmdcódigo específico elimina el archivo que se creó. Solo tienes que hacer esto en la últimacmdlínea.No use esta solución si un
#.batarchivo podría estar en su directorio de trabajo actual, ya que ese archivo se borrará.Recomendado: usar here-document para ignorar
cmdcomandos enbashAl colocar el
^carácter al final de lacmdlí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,cmdsolo 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
cmdlínea con exactamentehere-document delimiter, esta solución debería funcionar. Puede cambiarhere-document delimitera 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\nsaltos 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 0se ejecute el comando. Una vez queexit 0se alcanza, la ejecución del script terminará, ignorando los comandos de Windows debajo de él.En Windows
La primera línea ejecutará el
GOTO WINDOWScomando, omitiendo los comandos de Linux inmediatamente posteriores y continuando la ejecución en la:WINDOWSlí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 comoCRcaracteres.Haga una búsqueda y reemplazo (
Search>Replace...) y marque laExtended (\n, \r, \t, \0, \x...)opción.Escribe
\relFind 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
Replacebotón hasta que todos losCRcaracteres de retorno de carro ( ) se hayan eliminado de la parte superior de Linux. Asegúrese de dejar losCRcaracteres 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 (CRLF).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/nully luego comienza un comentario. En cmd, la tubería/dev/nullfalla 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:: exitel 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