116 votes

Un seul script à exécuter à la fois dans Windows batch et Linux Bash ?

Est-il possible d'écrire un seul fichier script qui s'exécute à la fois sous Windows (traité en .bat) et sous Linux (via Bash) ?

Je connais la syntaxe de base des deux, mais je n'ai pas compris. Il pourrait probablement exploiter une syntaxe obscure de Bash ou un bug du processeur batch de Windows.

La commande à exécuter peut être une simple ligne pour exécuter un autre script.

La motivation est de n'avoir qu'une seule commande de démarrage d'application pour Windows et Linux.

Mise à jour : La nécessité de l'interpréteur de commandes "natif" du système script est qu'il doit choisir la bonne version de l'interpréteur, se conformer à certaines variables d'environnement bien connues, etc. L'installation d'environnements supplémentaires comme CygWin n'est pas préférable - j'aimerais conserver le concept "download & run".

Le seul autre langage à envisager pour Windows est Windows Scripting Host - WSH, qui est prédéfini par défaut depuis 98.

6voto

Tex Killer Points 178

Il existe plusieurs façons d'exécuter différentes commandes sur bash y cmd avec le même script.

cmd ignorera les lignes qui commencent par :; comme indiqué dans d'autres réponses. Il ignorera également la ligne suivante si la ligne actuelle se termine par la commande rem ^ comme le ^ permettra d'échapper au saut de ligne et la ligne suivante sera traitée comme un commentaire par rem .

Quant à la fabrication bash ignorer le cmd les lignes, il y a plusieurs façons. J'ai énuméré quelques façons de le faire sans rompre la cmd des commandes :

Non-existant # commande (non recommandé)

S'il n'y a pas de # disponible sur cmd lorsque le script est exécuté, nous pouvons faire ceci :

# 2>nul & echo Hello cmd! & rem ^
echo 'Hello bash!' #

Le site # au début de l'élément cmd la ligne fait bash traiter cette ligne comme un commentaire.

Le site # à la fin de l'élément bash est utilisée pour commenter la ligne \r personnage, comme l'a souligné Brian Tompsett dans sa réponse . Sans cela, bash lancera une erreur si le fichier a \r\n les fins de ligne, requises par cmd .

En faisant # 2>nul on est en train de tromper cmd d'ignorer l'erreur d'un certain inexistant # tout en exécutant la commande qui suit.

N'utilisez pas cette solution s'il existe une # disponible sur le PATH ou si vous n'avez aucun contrôle sur les commandes disponibles à cmd .


Utilisation de echo d'ignorer le # caractère sur cmd

Nous pouvons utiliser echo avec sa sortie redirigée vers l'insert cmd commandes sur bash de la zone commentée :

echo >/dev/null # >nul & echo Hello cmd! & rem ^
echo 'Hello bash!' #

Depuis le # n'a pas de signification particulière sur cmd il est traité comme une partie du texte à l'adresse suivante echo . Tout ce que nous avions à faire, c'était de rediriger la sortie de la fonction echo et insérer d'autres commandes après elle.


Vide #.bat fichier

echo >/dev/null # 1>nul 2> #.bat
# & echo Hello cmd! & del #.bat & rem ^
echo 'Hello bash!' #

Le site echo >/dev/null # 1>nul 2> #.bat crée une ligne vide #.bat pendant que vous êtes sur cmd (ou remplace les #.bat le cas échéant), et ne fait rien tant que l'on est sur bash .

Ce fichier sera utilisé par le cmd ligne(s) qui suit(ent) même s'il existe une autre # sur le PATH .

Le site del #.bat sur le cmd -Un code spécifique supprime le fichier qui a été créé. Vous ne devez le faire que sur le dernier cmd ligne.

N'utilisez pas cette solution si un #.bat pourrait se trouver dans votre répertoire de travail actuel, car ce fichier sera effacé.


Recommandé : utiliser ici-document d'ignorer cmd commandes sur bash

:; echo 'Hello bash!';<<:
echo Hello cmd! & ^
:

En plaçant le ^ à la fin de l'élément cmd nous échappons le saut de ligne, et en utilisant : comme délimiteur du document, le contenu de la ligne du délimiteur n'aura aucun effet sur cmd . Par là, cmd n'exécutera sa ligne qu'après le : est terminée, ayant le même comportement que bash .

Si vous voulez avoir plusieurs lignes sur les deux plateformes et ne les exécuter qu'à la fin du bloc, vous pouvez faire ceci :

:;( #
  :;  echo 'Hello'  #
  :;  echo 'bash!'  #
:; );<<'here-document delimiter'
(
      echo Hello
      echo cmd!
) & rem ^
here-document delimiter

Tant qu'il n'y a pas cmd avec exactement here-document delimiter cette solution devrait fonctionner. Vous pouvez modifier here-document delimiter à tout autre texte.


Dans toutes les solutions présentées, les commandes ne seront exécutées qu'après la dernière ligne ce qui rend leur comportement cohérent s'ils font la même chose sur les deux plateformes.

Ces solutions doivent être enregistrées dans des fichiers avec \r\n comme des sauts de ligne, sinon ils ne fonctionneront pas sur cmd .

3voto

LolHens Points 96

J'utilise cette technique pour créer des fichiers jar exécutables. Comme le fichier jar/zip commence à l'en-tête du zip, je peux mettre un script universel pour exécuter ce fichier en haut :

#!/usr/bin/env sh\n
@ 2>/dev/null # 2>nul & echo off & goto BOF\r\n
:\n
<shell commands go here with \n line endings>
exit\n
\r\n
:BOF\r\n
<cmd commands go here with \r\n line endings>\r\n
exit /B %errorlevel%\r\n
}

Il est important de définir les fins de ligne comme indiqué ci-dessus car elles peuvent causer des problèmes sur les différentes plateformes. De même, l'instruction goto ne fonctionnera pas correctement dans certains cas si les fins de ligne appropriées sont manquantes autour de l'étiquette de saut.

La technique ci-dessus est celle que j'utilise actuellement. Vous trouverez ci-dessous une version plus ancienne avec une explication plus approfondie :

#!/usr/bin/env sh
@ 2>/dev/null # 2>nul & echo off
:; alias ::=''
:: exec java -jar $JAVA_OPTS "$0" "$@"
:: exit
java -jar %JAVA_OPTS% "%~dpnx0" %*
exit /B
  • La première ligne fait echo off dans cmd et n'imprime rien sur sh. Ceci est dû au fait que le @ dans sh génère une erreur qui est transmise à /dev/null et après cela, un commentaire commence. Sur cmd, le tuyau vers /dev/null échoue parce que le fichier n'est pas reconnu par Windows mais comme Windows ne détecte pas # en tant que commentaire, l'erreur est envoyée à nul . Puis il fait un écho au large. Comme la ligne entière est précédée d'un @ il ne s'imprime pas sur cmd.
  • Le second définit :: qui lance un commentaire dans cmd, à noop dans sh. Cela présente l'avantage que :: ne se réinitialise pas $? a 0 . Il utilise le " :; est une étiquette".
  • Je peux maintenant faire précéder les commandes sh de :: et ils sont ignorés dans cmd
  • Sur :: exit le sh script se termine et je peux écrire des commandes cmd
  • Seule la première ligne (shebang) est problématique dans cmd car elle imprimera command not found . Vous devez décider vous-même si vous en avez besoin ou non.

1voto

ShitalShah Points 2213

J'en avais besoin pour certains de mes paquets Python install scripts. La plupart des choses entre le fichier sh et bat sont les mêmes, mais quelques choses comme la gestion des erreurs sont différentes. Une façon de le faire est la suivante :

common.inc
----------
common statement1
common statement2

Puis vous appelez ceci depuis bash script :

linux.sh
--------
# do linux specific stuff
...
# call common code
source common.inc

Le fichier batch de Windows ressemble à ceci :

windows.bat
-----------
REM do windows specific things
...
# call common code
call common.inc

0voto

user1076662 Points 34

Essayez mon projet BashWin à https://github.com/skanga/bashwin qui utilise BusyBox pour la plupart des commandes Unix

-1voto

faham Points 146

Je vous suggère d'utiliser git-bash, c'est une émulation relativement légère et astucieuse mais indépendante de Linux bash sous Windows. Vous pourrez ainsi toujours écrire votre code pour Linux bash et l'exécuter sous Windows.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X