web-dev-qa-db-fra.com

À quoi sert `cmd / s`?

L'invite de commande Windows (cmd.exe) a une option /s paramètre , qui modifie le comportement de /c (exécutez une commande particulière puis quittez) ou /k (exécutez une commande particulière, puis affichez une invite Shell). Cette /s paramètre a évidemment quelque chose à voir avec une certaine gestion des citations obscures.

Les documents prêtent à confusion, mais pour autant que je sache, quand vous le faites cmd /csomething, et le something contient des guillemets, puis par défaut cmd supprimera parfois ces guillemets et /s lui dit de les laisser tranquilles.

Ce que je ne comprends pas, c'est quand la suppression du devis romprait quoi que ce soit, car c'est la seule fois /s ("supprimer le comportement de suppression de devis par défaut") serait nécessaire. Il supprime uniquement les guillemets sous un certain ensemble de conditions obscures, et l'une de ces conditions est que le premier caractère après le /c doit être un guillemet. Il ne s'agit donc pas de supprimer les guillemets autour des arguments; il s'agit soit de supprimer les guillemets autour du chemin d'accès à l'EXE que vous exécutez, soit autour de la ligne de commande entière (ou peut-être autour de la première moitié de la ligne de commande, ce qui serait bizarre).

  • Si le chemin d'accès à l'EXE est cité, par ex. cmd /c "c:\tools\foo.exe" arg1 arg2, alors les guillemets ne sont pas nécessaires, et si cmd veut les supprimer, très bien. (Il ne les supprimera pas si le chemin a un espace dans le nom - c'est une autre des règles arcaniques.) Je ne peux imaginer aucune raison de supprimer la suppression des guillemets, donc /s semble inutile.
  • Si la ligne de commande entière est citée, par ex. cmd /c "foo.exe arg1 arg2", il semble que la suppression des guillemets serait une nécessité, car il n'y a pas d'EXE nommé foo.exe arg1 arg2 sur le système; il semble donc que vous souhaitiez désactiver la suppression des devis à l'aide de /s briserait les choses. (En réalité, cependant, cela ne casse pas les choses: cmd /s /c "foo.exe arg1 arg2" fonctionne très bien.)

Y a-t-il une subtilité à /s ça m'échappe? Quand serait-il jamais nécessaire? Quand cela ferait-il une différence?

29
Joe White

Cmd/S est très utile car il vous évite d'avoir à vous soucier de "citer des devis". Rappelons que le /C argument signifie "exécuter cette commande comme si je l'avais tapée à l'invite, puis quitter".

Donc, si vous avez une commande compliquée que vous souhaitez transmettre à CMD.exe, vous devez soit vous souvenir des règles de citation des arguments de CMD, et échapper correctement toutes les citations, soit utiliser /S, qui déclenche une règle spéciale de non-analyse de "Supprimer d'abord et en dernier " et traiter tous les autres caractères comme la commande à exécuter inchangée ".

Vous l'utiliseriez là où vous souhaitez profiter des capacités du shell CMD, plutôt que d'appeler directement un autre programme. Par exemple, extension de variable d'environnement, redirection de sortie ou d'entrée, ou utilisation des intégrés CMD.exe.

Exemple:

Utiliser un shell intégré: cela s'exécute comme si vous aviez tapé DEL /Q/S "%TMP%\TestFile" à l'invite:

CMD.exe /S /C " DEL /Q/S "%TMP%\TestFile" "

Cela exécute SomeCommand.exe redirigeant la sortie standard vers un fichier temporaire et une erreur standard au même endroit:

CMD.exe /S /C " "%UserProfile%\SomeCommand.exe" > "%TMP%\TestOutput.txt" 2>&1 "

Alors qu'est-ce que /S vous donne un supplément? Principalement, cela vous évite d'avoir à vous soucier de citer les devis. Cela vous aide également lorsque vous n'êtes pas sûr si, par exemple, une variable d'environnement contient des guillemets. Dis le /S et mettez une citation supplémentaire au début et à la fin.

Vaguement liés: $ * en Bourne Shell.

Quelques antécédents

Rappelons que la liste des arguments de main () est un C-ism et Unix-ism. Le shell Unix/Linux (par exemple Bourne Shell, etc.) interprète la ligne de commande, supprime les arguments, développe les caractères génériques comme * aux listes de fichiers et transmet une liste d'arguments au programme appelé.

Donc, si vous dites:

$ vi *.txt

La commande vi voit par exemple ces arguments:

vi
a.txt
b.txt
c.txt
d.txt

En effet, unix/linux fonctionne en interne sur la base d'une "liste d'arguments".

Windows, qui dérive finalement de CP/M et VAX, n'utilise pas ce système en interne. Pour le système d'exploitation, la ligne de commande n'est qu'une seule chaîne de caractères. Il est de la responsabilité du programme appelé d'interpréter la ligne de commande, de développer les globes du fichier (* etc) et traiter les arguments entre guillemets.

Les arguments attendus par C doivent donc être piratés par la bibliothèque d'exécution C. Le système d'exploitation ne fournit qu'une seule chaîne avec les arguments en, et si votre langue n'est pas C (ou même si c'est le cas), elle ne peut pas être interprétée comme des arguments séparés par des espaces cités selon les règles de Shell, mais comme quelque chose de complètement différent.

17
Ben

Voici un exemple de la façon dont cela peut faire la différence.

Supposons que vous ayez deux exécutables: c:\Program.exe et c:\Program Files\foo.exe.

Si tu le dis

cmd /c "c:\Program Files\foo"

vous exécuterez foo.exe (sans argument) alors que si vous dites

cmd /s /c "c:\Program Files\foo"

vous exécuterez Program.exe avec Files\foo comme argument.

(Curieusement, dans le premier exemple, si foo.exe n'existait pas, Program.exe s'exécuterait à la place.)

Addendum: si vous deviez taper

 c:\Program Files\foo

à l'invite de commande, vous exécutez Program.exe (comme cela se produit avec cmd/s/c) plutôt que foo.exe (comme cela arrive avec seulement cmd/c). Ainsi, une des raisons d'utiliser/s serait si vous voulez vous assurer qu'une commande est analysée exactement de la même manière que si elle était tapée à l'invite de commande. Cela est probablement plus probable dans le scénario de la question liée à Michael Burr, où cmd.exe est lancé par CreateProcess plutôt qu'à partir d'un fichier de commandes ou de la ligne de commande elle-même.

Autrement dit, si vous dites

CreateProcess("cmd.exe", "cmd /s /c \"" MY_COMMAND "\"", ...)

puis la chaîne MY_COMMAND sera analysé exactement comme s'il avait été tapé à l'invite de commande. Si vous prenez une entrée de ligne de commande de l'utilisateur, ou si vous êtes une bibliothèque traitant une ligne de commande fournie par une application, c'est probablement une bonne idée. Par exemple, la fonction système de bibliothèque d'exécution C () peut être implémentée de cette manière.

10
Harry Johnston