Défi : écrire un seul fichier de script foo.cmd
qui peut être invoqué à partir de l' cmd.exe
invite Windows vanille (pas PowerShell, pas en mode administrateur), pour exécuter du code arbitraire spécifique à Windows ...
> .\foo.cmd
Hello Windows!
... mais aussi être invoquée sans modification à partir d'une invite de shell typique conforme à POSIX (Linux / OSX) (bash
, tcsh
ou zsh
), pour exécuter arbitraire code spécifique POSIX:
$ chmod a+x foo.cmd
$ ./foo.cmd
Hello POSIX!
... sans nécessiter l'installation ou la création d'interprètes / outils tiers.
Je sais que c'est possible, mais avec cruft (c'est-à-dire sous Windows, une ou deux lignes de déchets / message d'erreur sont imprimées sur stderr ou stdout avant "Bonjour Windows!").
Le critère gagnant est la minimisation du (premier) nombre de lignes de découpe et (deuxièmement) du nombre de caractères de gravure.
Cruft peut être défini comme n'importe quelle sortie de console (stdout ou stderr) qui n'est pas produite par le code de charge utile (arbitraire). Les lignes vides sont comptées dans le nombre de lignes. Les sauts de ligne ne sont pas comptés dans le nombre de caractères. Les scores de Cruft doivent être additionnés sur les deux plates-formes. cls
Méconnaissons des mécanismes comme celui-ci qui balaient la cruauté mais au prix de masquer également la sortie du terminal précédent. Si Windows fait écho à vos commandes parce que vous ne l'avez pas @echo off
encore fait, excluons les caractères qu'il dépense lors de l'impression du répertoire et de l'invite actuels.
Un critère secondaire est la simplicité / élégance de la solution à l'intérieur foo.cmd
: si "infrastructure" est définie comme n'importe quel caractère non directement impliqué dans le code de charge utile arbitraire, minimisez d'abord le nombre de lignes qui contiennent des caractères d'infrastructure, puis le nombre total d'infrastructure personnages.
Félicitations supplémentaires si la partie POSIX fonctionne malgré le fichier ayant des fins de ligne CRLF! (Je ne suis pas sûr que la dernière partie soit même possible.)
Ma solution existante, que je posterai ici une fois que d'autres auront eu la chance, utilise 6 lignes de code d'infrastructure (52 caractères hors newlines). Il produit 5 lignes de découpe, dont deux sont vides, qui se produisent toutes sur Windows (30 caractères excluant les sauts de ligne et excluant le répertoire / la chaîne d'invite actuelle qui apparaît sur deux de ces lignes).
Réponses:
0 lignes de cruft, 0 caractères de cruft, 2 infra. lignes, 21 infra. caractères, CRLF ok
Suppression de l'autre solution.
17 caractères utilisant
exit /b
de la réponse de Digital Trauma:la source
: command not found
chaque fois qu'une ligne vierge se glissait dans la charge utile posix, mais j'ai finalement compris que ce n'était pas:
sur la première ligne mais plutôt à cause des CRLF non protégés par#
. C'était une nouvelle pour moi qu'une#!
ligne n'est pas nécessaire - qui était responsable de deux des lignes de Windows croutées dans ma version précédente.: ` >&3` \
à chaque ligne de la charge utile, je suppose que vous pourriez dire que son coût d'infrastructure est arbitrairement élevé.#
nécessaire?Score 0 cruft + 4 lignes infra + 32 caractères infra. LF & CRLF OK.
Ceci est basé sur ce que j'ai trouvé sur ce blog , avec les bits Amiga et autres lignes inutiles supprimés. J'ai caché les lignes DOS entre guillemets commentés au lieu d'utiliser la
\
ligne continue, afin que cela puisse fonctionner avec CRLF et LF.Avec les terminaisons de ligne DOS CRLF ou * nix LF, cela fonctionne sur Ubuntu, OSX et wine:
Pour créer cela exactement (avec des CRLF) sur une machine * nix (y compris OSX), collez ce qui suit dans un terminal:
la source
dosix
est aussi un joli nom. Mais sur mon Mac (OS 10.9.4, Darwin Kernel Version 13.3.0, GNU bash version 3.2.51), il ne fonctionne pas avec:./dosix.cmd: line 13: syntax error: unexpected end of file
Une idée pourquoi?Je publierai déjà la solution que j'utilisais, car elle a déjà été battue. C'est la courtoisie d'un de mes collègues qui, je pense, doit avoir lu la même entrée de blog que Digital Trauma .
#!
ligne s'en fiche (donc pour les interprètes standard commesh
et amis, il échoue)la source
#!
, ce qui signifie que la vôtre est jusqu'à présent la seule réponse à être un script valide sur un système POSIX. Bien sûr, certains des autres peuvent s'exécuter si - mais seulement s'ils sont démarrés à partir d'un shell avec une solution de contournement pour les scripts défectueux.#!
ligne manquante , mais ils utiliseront des shells différents pour interpréter le script. Cela signifie qu'un "script" qui ne commence pas par#!
doit être valide non seulement dans un shell, mais dans tous les shell par lesquels il pourrait être interprété de manière plausible. Mais pire encore, cela ne fonctionne que lorsqu'il est démarré à partir d'un autre shell. Un tel script peut fonctionner à partir de la ligne de commande, mais pas dans le contexte où vous avez finalement l'intention de l'utiliser.#!
ligne dans ma réponse modifiée (1 ligne d'infrastructure avec 21 caractères) peut être combinée avec la réponse de quelqu'un d'autre à un coût de Windows de 2 lignes (dont l'une est vide) ou 23 caractères.Résumé / synthèse des réponses et discussion
C'était amusant et j'ai beaucoup appris.
Une partie spécifique à Windows est inévitable si, sur votre système POSIX, vous devez démarrer votre script avec une
#!
ligne. Si vous n'avez pas d'autre choix que de le faire, alors cette ligne:est probablement le meilleur qu'il puisse obtenir. Il provoque une ligne vide et une ligne de cruft en sortie sur la console Windows. Cependant, vous pourrez peut- être vous en sortir sans
#!
ligne: sur la plupart des systèmes, l'un des interpréteurs de shell habituels finira par exécuter le script (le problème est qu'il n'est pas universellement prévisible de quel interprète ce sera - cela dépend, mais pas nécessairement identique au shell que vous utilisez pour appeler la commande).Au-delà de cette première ligne délicate, il y avait des solutions sans cruauté vraiment ingénieuses. La soumission gagnante de jimmy23013 ne comprenait que deux courtes lignes d'infrastructure et utilisait le double rôle du
:
personnage pour mettre en œuvre une ligne "silencieuse" sur les deux plates-formes (en tant que no-op de factosh
et amis, et en tant que label marqueurcmd.exe
):Il est possible d'exécuter un tel script sur des systèmes POSIX même malgré les fins de ligne CRLF, mais pour ce faire, pour la plupart des interprètes, vous devez terminer chaque ligne de votre section POSIX (même les lignes vides) par un commentaire ou un caractère de commentaire.
Enfin, voici deux variantes d'une solution que j'ai développée en fonction de l'apport de chacun. Ils pourraient être presque le meilleur de tous les mondes, en ce sens qu'ils minimisent les dommages causés par le manque
#!
et rendent la compatibilité CRLF encore plus fluide. Deux lignes d'infrastructure supplémentaires sont nécessaires. Une seule ligne (standardisée) doit être interprétée par le shell POSIX imprévisible, et cette ligne vous permet de sélectionner le shell pour le reste du script (bash
dans l'exemple suivant):Une partie de la beauté de ces solutions heredoc est qu'elles sont toujours robustes au CRLF: tant que
<<:Z
vient à la fin de la ligne, le processeur heredoc recherchera et trouvera le jeton:Z\r
Pour finir, vous pouvez vous débarrasser de ces commentaires embêtants de fin de ligne tout en conservant la robustesse CRLF, en supprimant les
\r
caractères avant de passer les lignes au shell. Cela place un peu plus de confiance dans le shell imprévisible (ce serait bien d'utiliser à la{ tr -d \\r|bash;}
place de(tr -d \\r|bash)
mais les accolades sont une syntaxe bash uniquement):Bien sûr, cette approche sacrifie la possibilité de canaliser l'entrée stdin dans le script.
la source