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.

109voto

binki Points 479

Ce que j'ai fait, c'est utiliser la syntaxe de l'étiquette de cmd comme marqueur de commentaire . Le caractère d'étiquette, un deux-points ( : ), est équivalent à true dans la plupart des shells POSIX. Si vous suivez immédiatement le caractère d'étiquette par un autre caractère qui ne peut pas être utilisé dans une commande de type GOTO puis en commentant votre cmd script ne devraient pas affecter votre cmd code.

L'astuce consiste à placer des lignes de code après la séquence de caractères " :; ". Si vous écrivez principalement des scripts en une seule ligne ou, comme cela peut être le cas, si vous pouvez écrire une ligne de sh pour de nombreuses lignes de cmd la solution suivante pourrait convenir. N'oubliez pas que toute utilisation de $? doit être avant votre prochain colon : parce que : réinitialise $? à 0.

:; echo "Hi, I’m ${SHELL}."; exit $?
@ECHO OFF
ECHO I'm %COMSPEC%

Un exemple très artificiel de gardiennage $? :

:; false; ret=$?
:; [ ${ret} = 0 ] || { echo "Program failed with code ${ret}." >&2; exit 1; }
:; exit
ECHO CMD code.

Une autre idée pour passer outre cmd est d'utiliser heredocs de sorte que sh traite les cmd comme une chaîne inutilisée et cmd l'interprète. Dans ce cas, nous veillons à ce que le délimiteur de notre heredoc soit à la fois entre guillemets (pour empêcher les sh de faire n'importe quelle sorte d'interprétation sur son contenu lorsqu'il est exécuté avec sh ) et commence par : de sorte que cmd passe dessus comme n'importe quelle autre ligne commençant par : .

:; echo "I am ${SHELL}"
:<<"::CMDLITERAL"
ECHO I am %COMSPEC%
::CMDLITERAL
:; echo "And ${SHELL} is back!"
:; exit
ECHO And back to %COMSPEC%

En fonction de vos besoins ou de votre style de codage, les entrelacs cmd y sh Le code peut ou non avoir un sens. L'utilisation des hérédocs est une méthode pour réaliser un tel entrelacement. Cette méthode pourrait toutefois être étendue avec l'option GOTO technique :

:<<"::CMDLITERAL"
@ECHO OFF
GOTO :CMDSCRIPT
::CMDLITERAL

echo "I can write free-form ${SHELL} now!"
if :; then
  echo "This makes conditional constructs so much easier because"
  echo "they can now span multiple lines."
fi
exit $?

:CMDSCRIPT
ECHO Welcome to %COMSPEC%

Les commentaires universels, bien sûr, peuvent être faits avec la séquence de caractères : # o :;# . L'espace ou le point-virgule sont nécessaires car sh considère # pour faire partie du nom d'une commande s'il n'est pas le premier caractère d'un identifiant. Par exemple, vous pourriez vouloir écrire des commentaires universels dans les premières lignes de votre fichier avant d'utiliser la commande GOTO pour diviser votre code. Vous pourrez alors informer votre lecteur de la raison pour laquelle votre script est écrit si bizarrement :

: # This is a special script which intermixes both sh
: # and cmd code. It is written this way because it is
: # used in system() shell-outs directly in otherwise
: # portable code. See https://stackoverflow.com/questions/17510688
: # for details.
:; echo "This is ${SHELL}"; exit
@ECHO OFF
ECHO This is %COMSPEC%

Ainsi, quelques idées et moyens d'accomplir sh y cmd -compatible scripts sans effets secondaires sérieux pour autant que je sache (et sans avoir cmd sortie '#' is not recognized as an internal or external command, operable program or batch file. ).

12voto

Je voulais faire un commentaire, mais je ne peux qu'ajouter une réponse pour le moment.

Les techniques données sont excellentes et je les utilise également.

Il est difficile de conserver un fichier qui contient deux types de sauts de ligne, à savoir /n pour la partie bash et /r/n pour la partie Windows. La plupart des éditeurs essaient d'appliquer un schéma commun de retour à la ligne en devinant le type de fichier que vous éditez. De plus, la plupart des méthodes de transfert du fichier sur Internet (en particulier sous forme de fichier texte ou script) blanchissent les sauts de ligne, de sorte que vous pouvez commencer avec un type de saut de ligne et finir avec l'autre. Si vous faites des hypothèses sur les sauts de ligne et que vous donnez ensuite votre script à quelqu'un d'autre pour qu'il l'utilise, il pourrait trouver que cela ne fonctionne pas pour lui.

L'autre problème concerne les systèmes de fichiers (ou CD) montés en réseau qui sont partagés entre différents types de systèmes (en particulier lorsque vous ne pouvez pas contrôler les logiciels disponibles pour l'utilisateur).

Il faut donc utiliser le saut de ligne DOS de /r/n et aussi protéger le script bash du DOS /r en mettant un commentaire à la fin de chaque ligne ( # ). Vous ne pouvez pas non plus utiliser les continuations de ligne en bash parce que la fonction /r les fera se briser.

De cette façon, quiconque utilise le script, et dans n'importe quel environnement, il fonctionnera alors.

J'utilise cette méthode en conjonction avec la création de Makefiles portables !

8voto

remik Points 121

Ce qui suit fonctionne pour moi sans aucune erreur ni message d'erreur avec Bash 4 et Windows 10, contrairement aux réponses ci-dessus. Je nomme le fichier "whatever.cmd", fais chmod +x pour le rendre exécutable sous linux, et lui donner des terminaisons de ligne unix ( dos2unix ) pour garder bash tranquille.

:; if [ -z 0 ]; then
  @echo off
  goto :WINDOWS
fi

if [ -z "$2" ]; then
  echo "usage: $0 <firstArg> <secondArg>"
  exit 1
fi

# bash stuff
exit

:WINDOWS
if [%2]==[] (
  SETLOCAL enabledelayedexpansion
  set usage="usage: %0 <firstArg> <secondArg>"
  @echo !usage:"=!
  exit /b 1
)

:: windows stuff

7voto

Velkan Points 3358

Vous pouvez partager des variables :

:;SET() { eval $1; }

SET var=value

:;echo $var
:;exit
ECHO %var%

7voto

A-Diddy Points 151

Les réponses précédentes semblent couvrir à peu près toutes les options et m'ont beaucoup aidé. J'inclus cette réponse ici juste pour démontrer le mécanisme que j'ai utilisé pour inclure à la fois un script Bash et un script Windows CMD dans le même fichier.

LinuxWindowsScript.bat

echo >/dev/null # >nul & GOTO WINDOWS & rem ^
echo 'Processing for Linux'

# ***********************************************************
# * NOTE: If you modify this content, be sure to remove carriage returns (\r) 
# *       from the Linux part and leave them in together with the line feeds 
# *       (\n) for the Windows part. In summary:
# *           New lines in Linux: \n
# *           New lines in Windows: \r\n 
# ***********************************************************

# Do Linux Bash commands here... for example:
StartDir="$(pwd)"

# Then, when all Linux commands are complete, end the script with 'exit'...
exit 0

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

:WINDOWS
echo "Processing for Windows"

REM Do Windows CMD commands here... for example:
SET StartDir=%cd%

REM Then, when all Windows commands are complete... the script is done.

Résumé

Dans Linux

La première ligne ( echo >/dev/null # >nul & GOTO WINDOWS & rem ^ ) sera ignorée et le script s'écoulera sur chaque ligne qui le suit immédiatement jusqu'à ce que la balise exit 0 est exécutée. Une fois que exit 0 est atteint, l'exécution du script se terminera, en ignorant les commandes Windows qui lui sont inférieures.

Dans Windows

La première ligne exécutera le GOTO WINDOWS en sautant les commandes Linux qui la suivent immédiatement et en poursuivant l'exécution à la commande :WINDOWS ligne.

Suppression des retours chariot dans Windows

Comme j'éditais ce fichier sous Windows, j'ai dû systématiquement supprimer les retours chariot ( \r ) des commandes Linux, sinon j'obtenais des résultats anormaux lors de l'exécution de la partie Bash. Pour ce faire, j'ai ouvert le fichier dans Notepad++ et a fait ce qui suit :

  1. Activez l'option permettant de visualiser les caractères de fin de ligne ( View > Show Symbol > Show End of Line ). Les retours de chariot seront alors affichés comme CR des personnages.

  2. Effectuez une recherche et un remplacement ( Search > Replace... ) et vérifiez le Extended (\n, \r, \t, \0, \x...) option.

  3. Type \r dans le Find what : et effacez le champ Replace with : le champ, donc il n'y a rien dedans.

  4. En commençant par le haut du fichier, cliquez sur le bouton Replace jusqu'à ce que tous les retours de chariot ( CR ) ont été supprimés de la partie supérieure de Linux. Veillez à laisser le retour chariot ( CR ) pour la partie Windows.

Le résultat devrait être que chaque commande Linux se termine par un simple saut de ligne ( LF ) et chaque commande Windows se termine par un retour chariot et un saut de ligne ( CR LF ).

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