Est-il possible d'écrire un seul fichier de script qui s'exécute à la fois sous Windows (traité comme .bat) et 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 problème de processeur par lots Windows.
La commande à exécuter peut être juste une seule 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: Le besoin du script shell "natif" du système est qu'il doit choisir la bonne version d'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 garder le concept " télécharger et exécuter ".
Le seul autre langage à prendre en compte pour Windows est Windows Scripting Host - WSH, qui est prédéfini par défaut depuis 98.
la source
cp
intégrées, ou vice versa, donc l'écriture de deux scripts séparés peut être pédagogiquement meilleure que les techniques avancées présentées ici.Réponses:
Ce que j'ai fait, c'est d' utiliser la syntaxe d'étiquette de cmd comme marqueur de commentaire . Le caractère d'étiquette, un deux-points (
:
), est équivalent àtrue
dans la plupart des shells POSIXish. Si vous suivez immédiatement le caractère d'étiquette par un autre caractère qui ne peut pas être utilisé dans aGOTO
, le commentaire de votrecmd
script ne devrait pas affecter votrecmd
code.Le hack consiste à mettre des lignes de code après la séquence de caractères «
:;
». Si vous écrivez principalement des scripts à une seule ligne ou, comme cela peut être le cas, vous pouvez écrire une ligne desh
pour plusieurs lignes decmd
, ce qui suit peut convenir. N'oubliez pas que toute utilisation de$?
doit être avant votre prochain deux:
- points car il est:
remis$?
à 0.Un exemple très artificiel de gardiennage
$?
:Une autre idée pour ignorer le
cmd
code est d'utiliser heredocs afin desh
traiter lecmd
code comme une chaîne inutilisée et de l'cmd
interpréter. Dans ce cas, nous nous assurons que le délimiteur de notre heredoc est à la fois entre guillemets (pour évitersh
de faire toute sorte d'interprétation de son contenu lors de l'exécution avecsh
) et commence par:
pour qu'ilcmd
saute dessus comme toute autre ligne commençant par:
.Selon vos besoins ou votre style de codage, l'entrelacement
cmd
et lesh
code peuvent ou non avoir un sens. L'utilisation d'heredocs est une méthode pour effectuer un tel entrelacement. Cela pourrait cependant être étendu avec laGOTO
technique :Les commentaires universels, bien sûr, peuvent être faits avec la séquence de caractères
: #
ou:;#
. L'espace ou le point-virgule sont nécessaires carsh
considère#
comme faisant partie d'un nom de commande si ce n'est pas le premier caractère d'un identifiant. Par exemple, vous souhaiterez peut-être écrire des commentaires universels dans les premières lignes de votre fichier avant d'utiliser laGOTO
méthode pour fractionner votre code. Ensuite, vous pouvez informer votre lecteur de la raison pour laquelle votre script est écrit si curieusement:Ainsi, quelques idées et façons d'accomplir des scripts compatibles
sh
etcmd
sans effets secondaires sérieux pour autant que je sache (et sans avoir decmd
sortie'#' is not recognized as an internal or external command, operable program or batch file.
).la source
.cmd
extension, sinon il ne fonctionnera pas sous Windows. Y a-t-il une solution de contournement?.cmd
et de les marquer comme exécutables. De cette façon, l'exécution du script à partir du shell par défaut sous Windows ou sous Unix fonctionnera (testé uniquement avec bash). Parce que je ne peux pas penser à un moyen d'inclure un shebang sans que cmd se plaigne bruyamment, vous devez toujours invoquer le script via le shell. Par exemple, assurez-vous d'utiliserexeclp()
ouexecvp()
(je pensesystem()
que c'est la «bonne» façon pour vous) plutôt queexecl()
ouexecv()
(ces dernières fonctions ne fonctionneront que sur les scripts avec shebangs car elles vont plus directement vers le système d'exploitation).<Exec/>
MSBuild Task ) plutôt que sous forme de fichiers batch indépendants. Peut-être que si j'ai un peu de temps dans le futur, je mettrai à jour la réponse avec les informations contenues dans ces commentaires…vous pouvez essayer ceci:
Vous devrez probablement utiliser
/r/n
comme nouvelle ligne au lieu d'un style unix.Si je me souviens bien, la nouvelle ligne unix n'est pas interprétée comme une nouvelle ligne par les.bat
scripts.Une autre façon est de créer un#.exe
fichier dans le chemin qui ne fait rien dans de la même manière que ma réponse ici: est-il possible d'intégrer et d'exécuter VBScript dans un fichier batch sans utiliser de fichier temporaire?ÉDITER
La réponse du binki est presque parfaite mais peut encore être améliorée:
Il utilise à nouveau l'
:
astuce et le commentaire sur plusieurs lignes. On dirait que cmd.exe (au moins sur windows10) fonctionne sans problème avec les EOL de style unix, alors assurez-vous que votre script est converti au format linux. (la même approche a déjà été utilisée ici et ici ). Bien que l'utilisation de shebang produise toujours une sortie redondante ...la source
/r/n
à la fin des lignes causera de nombreux maux de tête dans le script bash à moins que vous ne terminiez chaque ligne par un#
(ie#/r/n
) - de cette façon, le\r
sera traité comme faisant partie du commentaire et ignoré.# 2>NUL & ECHO Welcome to %COMSPEC%.
parvient à masquer l'erreur concernant la#
commande introuvable parcmd
. Cette technique est utile lorsque vous devez écrire une ligne autonome qui ne sera exécutée que parcmd
( par exemple, en aMakefile
).Je voulais faire un commentaire, mais je ne peux ajouter qu'une réponse pour le moment.
Les techniques données sont excellentes et je les utilise aussi.
Il est difficile de conserver un fichier contenant deux types de sauts de ligne, celui
/n
de la partie bash et/r/n
la partie windows. La plupart des éditeurs essaient d'appliquer un schéma de saut de ligne commun 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 de script) blanchiront les sauts de ligne, vous pouvez donc commencer par un type de saut de ligne et finir par l'autre. Si vous avez fait des hypothèses sur les sauts de ligne et que vous avez ensuite donné votre script à quelqu'un d'autre, il se peut que cela ne fonctionne pas pour eux.L'autre problème concerne les systèmes de fichiers (ou CD) montés sur le 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
/r/n
et protéger également le script bash du DOS/r
en mettant un commentaire à la fin de chaque ligne (#
). Vous ne pouvez pas non plus utiliser de continuations de ligne dans bash car le/r
entraînera à se casser.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!
la source
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 "what.cmd", fais-le
chmod +x
pour le rendre exécutable sous Linux, et lui donne des fins de ligne unix (dos2unix
) pour que bash reste silencieux.la source
Vous pouvez partager des variables:
la source
Il existe plusieurs manières d'exécuter différentes commandes sur
bash
etcmd
avec le même script.cmd
ignorera les lignes commençant par:;
, comme mentionné dans d'autres réponses. Il ignorera également la ligne suivante si la ligne actuelle se termine par la commanderem ^
, car le^
caractère échappera au saut de ligne et la ligne suivante sera traitée comme un commentaire parrem
.Quant à faire
bash
ignorer lescmd
lignes, il existe de multiples façons. J'ai énuméré quelques façons de le faire sans casser lescmd
commandes:#
Commande inexistante (non recommandée)S'il n'y a pas de
#
commande disponiblecmd
lors de l'exécution du script, nous pouvons le faire:Le
#
caractère au début de lacmd
ligne permet debash
traiter cette ligne comme un commentaire.Le
#
caractère à la fin de labash
ligne est utilisé pour commenter le\r
personnage, comme l'a souligné Brian Tompsett dans sa réponse . Sans cela,bash
générera une erreur si le fichier a des\r\n
fins de ligne, requises parcmd
.Ce faisant
# 2>nul
, nous avons du malcmd
à ignorer l'erreur d'une#
commande inexistante , tout en exécutant la commande qui suit.N'utilisez pas cette solution si une
#
commande est disponible sur lePATH
ou si vous n'avez aucun contrôle sur les commandes disponibles pourcmd
.Utiliser
echo
pour ignorer le#
personnage surcmd
Nous pouvons utiliser
echo
avec sa sortie redirigée pour insérer descmd
commandes dansbash
la zone commentée de:Étant donné que le
#
caractère n'a pas de signification particulièrecmd
, il est traité comme une partie du texte àecho
. Tout ce que nous avions à faire était de rediriger la sortie de laecho
commande et d'insérer d'autres commandes après.#.bat
Fichier videLa
echo >/dev/null # 1>nul 2> #.bat
ligne crée un#.bat
fichier vide lorsqu'elle est activéecmd
(ou remplace l'existant#.bat
, le cas échéant) et ne fait rien lorsqu'elle est activéebash
.Ce fichier sera utilisé par la ou les
cmd
lignes qui suivent même s'il existe une autre#
commande sur lePATH
.La
del #.bat
commande sur lecmd
code spécifique supprime le fichier qui a été créé. Vous ne devez le faire que sur la dernièrecmd
ligne.N'utilisez pas cette solution si un
#.bat
fichier peut se trouver dans votre répertoire de travail actuel, car ce fichier sera effacé.Recommandé: utiliser here-document pour ignorer les
cmd
commandes surbash
En plaçant le
^
caractère à la fin de lacmd
ligne, nous échappons au saut de ligne, et en utilisant:
comme délimiteur ici-document, le contenu de la ligne de délimitation n'aura aucun effet surcmd
. De cette façon,cmd
n'exécutera sa ligne qu'une fois la:
ligne terminée, ayant le même comportement quebash
.Si vous souhaitez avoir plusieurs lignes sur les deux plates-formes et ne les exécuter qu'à la fin du bloc, vous pouvez le faire:
Tant qu'il n'y a pas de
cmd
ligne avec exactementhere-document delimiter
, cette solution devrait fonctionner. Vous pouvez passerhere-document delimiter
à n'importe quel autre texte.Dans toutes les solutions présentées, les commandes ne seront exécutées qu'après la dernière ligne , rendant leur comportement cohérent si elles font la même chose sur les deux plates-formes.
Ces solutions doivent être enregistrées dans des fichiers avec des
\r\n
sauts de ligne, sinon elles ne fonctionneront pascmd
.la source
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
Résumé
Sous Linux
La première ligne (
echo >/dev/null # >nul & GOTO WINDOWS & rem ^
) sera ignorée et le script parcourra chaque ligne qui la suivra immédiatement jusqu'à ce que laexit 0
commande soit exécutée. Une foisexit 0
atteint, l'exécution du script se terminera, ignorant les commandes Windows en dessous.Sous Windows
La première ligne exécutera la
GOTO WINDOWS
commande, en ignorant les commandes Linux qui la suivent immédiatement et en poursuivant l'exécution sur la:WINDOWS
ligne.Suppression des retours chariot dans Windows
Depuis que j'éditions ce fichier sous Windows, j'ai dû systématiquement supprimer les retours chariot (\ r) des commandes Linux ou bien 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 j'ai fait ce qui suit:
Activez l'option pour l' affichage des caractères de fin de ligne (
View
>Show Symbol
>Show End of Line
). Les retours chariot s'afficheront alors sous forme deCR
caractères.Effectuez un Rechercher et remplacer (
Search
>Replace...
) et cochez l'Extended (\n, \r, \t, \0, \x...)
option.Tapez
\r
leFind what :
champ et videz leReplace with :
champ pour qu'il n'y ait rien dedans.En commençant par le haut du fichier, cliquez sur le
Replace
bouton jusqu'à ce que tous les caractères de retour chariot (CR
) aient été supprimés de la partie supérieure de Linux. Veillez à laisser les caractères de 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
).la source
J'utilise cette technique pour créer des fichiers jar exécutables. Étant donné que le fichier jar / zip commence à l'en-tête zip, je peux mettre un script universel pour exécuter ce fichier en haut:
@
in sh renvoie une erreur qui est redirigée vers/dev/null
et après cela, un commentaire démarre. Sur cmd, le canal/dev/null
échoue car le fichier n'est pas reconnu sur Windows, mais comme Windows ne détecte pas#
comme un commentaire, l'erreur est redirigéenul
. Ensuite, il fait un écho. Parce que toute la ligne est précédée d'un,@
il ne reçoit pas d'impression sur cmd.::
, qui commence un commentaire dans cmd, à noop dans sh. Cela a l'avantage qui::
ne se réinitialise$?
pas0
. Il utilise l':;
astuce " est une étiquette".::
et elles sont ignorées dans cmd:: exit
le script sh se termine et je peux écrire des commandes cmdcommand not found
. Vous devez décider vous-même si vous en avez besoin ou non.la source
J'en avais besoin pour certains de mes scripts d'installation de package Python. La plupart des choses entre les fichiers sh et bat sont les mêmes, mais peu de choses comme la gestion des erreurs sont différentes. Une façon de procéder est la suivante:
Ensuite, vous appelez cela à partir du script bash:
Le fichier de commandes Windows ressemble à ceci:
la source
Essayez mon projet BashWin sur https://github.com/skanga/bashwin qui utilise BusyBox pour la plupart des commandes Unix
la source
Il existe des outils de construction indépendants de la plate-forme comme Ant ou Maven avec une syntaxe xml (basée sur Java). Ainsi, vous pouvez réécrire tous vos scripts dans Ant ou Maven et les exécuter malgré le type d'os. Ou vous pouvez simplement créer un script wrapper Ant, qui analysera le type d'os et exécutera le script bat ou bash approprié.
la source