Comment conserver la valeur d'une variable en dehors d'un script Windows batch qui utilise le mode "delayed expansion local"?

contexte : je dois appeler un script Windows batch qui mettrait à jour mon PATH en ajoutant un autre chemin " xxx "à la fin de celui-ci, mais:

  • sans aucun duplicata

    (si j'ajoute ' xxx 'à un chemin comme' aaa;xxx;bbb ', j'ai besoin d'une mise à jour de PATH comme ' aaa;bbb;xxx ')
  • sans aucune agrégation

    (Je peux appeler le script à plusieurs reprises sans finir par ' aaa;bbb;xxx;xxx;xxx;... ')

Ce que j'ai essayé:

la fonction suivante s'occupe de tout duplicata et fait le travail

:cleanAddPath -- remove %~1 from PATH, add it at the end of PATH
SETLOCAL ENABLEDELAYEDEXPANSION
set PATH=!PATH:%~2=!
set PATH=!PATH:;;=;!
set PATH=%PATH%;%~2
set P=!P:;;=;!
echo %PATH%
echo -------------
ENDLOCAL  
exit /b

mais, il a besoin de expansion retardée mode local , ce qui signifie: à la fin du script (ou ici, à la fin de la fonction cleanAddPath ), tout ce qui a été défini pour %PATH% est jeté .

je pourrais demander aux utilisateurs (pour lesquels j'écris le script) de lancer leur cmd avec une option cmd /V:ON (activant l'extension retardée, sinon désactivée par défaut), mais ce n'est pas pratique.

Comment puis-je modifier la variable PATH comme je l'ai décrit ci-dessus, et la mettre à jour dans ma session DOS après en appelant ledit script?

8
demandé sur VonC 2012-08-18 20:16:07

3 réponses

de La page " DOS en Fonction de la Collection " donne un excellent exemple de la façon dont une fonction peut renvoyer une valeur dans le DOS, même lors de l'utilisation de expansion retardée mode:

la fonction suivante mettra à jour n'importe quelle variable que vous voulez avec un ajout PATH :

:cleanAddPath -- remove %~2 from %~1, add it at the end of %~1
SETLOCAL ENABLEDELAYEDEXPANSION
set P=!%~1!
set P=!P:%~2=!
set P=!P:;;=;!
set P=!P!;%~2
set P=!P:;;=;!
(ENDLOCAL & REM.-- RETURN VALUES
  SET "%~1=%P%"
)
exit /b

Note la concaténation des chemins à l'aide. jeb commentaires :

la ligne set P=%P%;%~2 est critique si votre chemin contient des espions comme dans C:\Documents&Settings .

Mieux vaut changer " P=!P!;%~2 ".

le SET "%~1=%P%" est la partie qui permet de mémoriser (dans la variable représentée par %~1 ) la valeur que vous avez définie en utilisant des fonctionnalités d'extension retardée.

J'ai d'abord utilisé SET "%~1=%P%" ! , mais jeb commentaires :

la commande SET "%~1=%P%" ! pourrait être simplifiée à SET "%~1=%P%" car le point d'exclamation arrière n'a qu'un (bon) effet en mode d'expansion retardée et si vous avez préparé %P% avant.

pour mettre à jour votre variable PATH , vous appelleriez votre fonction avec:

call :cleanAddPath PATH "C:\my\path\to\add"

et il persistera après avoir quitté ce script, pour votre session DOS actuelle.

dbenham 's réponse points à une plus forte réponse (upvoted), mais dans mon cas, ce script est assez.

6
répondu VonC 2017-05-23 12:01:58

Le problème n'est pas aussi simple que vous le pensez. Il y a un certain nombre de problèmes qui peuvent briser votre code avant qu'il arrive à la fin où il doit retourner la valeur mise à jour à travers la barrière ENDLOCAL .

j'ai déjà répondu à cette question comme une extension d'une réponse que j'ai fournie pour une question similaire. Voir Comment vérifier si le répertoire existe dans %PATH%? . Dans cette réponse, je présente une vaste liste de questions qui compliquent le problème.

Le code en bas de la réponse liée montre comment ajouter de manière fiable un chemin s'il n'existe pas déjà dans PATH , et il montre également comment retourner de manière fiable la valeur à travers la barrière ENDLOCAL .

les éditions suivantes sont de VonC dans une tentative de mettre réellement la réponse ici au lieu de juste un lien à la réponse. Je vais préserver l'édition, mais je trouve qu'il est difficile de suivre sans le contexte de le plein lié réponse.

[La réponse montre comment fiable de retourner la valeur] à l'aide de la set "%~1=%var%" ! truc (avec la fuite ' ! ')

ce fil comprend:

ce n'est pas clair pour moi. Comment un point d'exclamation derrière la dernière citation peut-il influencer le contenu variable?

La règle simple pour le retard expansion est:

Pour chaque caractère de la ligne faire:

  • si c'est un caret ( ^ ) le caractère suivant n'a pas de signification particulière, le caret lui-même est enlevé
  • s'il s'agit d'un point d'exclamation, cherchez le prochain point d'exclamation (les carets ne sont pas observés ici), puis passez au contenu de la variable
  • si aucun point d'exclamation n'est trouvé dans cette phase, le résultat est écarté, le résultat de la phase avant est utilisé à la place (important pour les carets)

ainsi, à ce point la différence doit être claire, les carets sont enlevés même si le point d'exclamation n'ont pas d'autre effet dans une ligne.

Exemple:

@echo off
setlocal EnableDelayedExpansion

echo one caret^^
echo none caret^^  !

set "var1=one caret^"
set "var2=none caret^" !

echo !var1!
echo !var2!
----- OUTPUT ----
one caret^
none caret
one caret^
one caret
3
répondu dbenham 2017-05-23 12:24:56

Yay! Finalement obtenu ce travail avec le code de test suivant:

@echo off
Setlocal enabledelayedexpansion

Set p="hello world"

( endlocal & rem return

   Set "a1=%p%"

)

Set a1

Ce sorties:

a1="hello world"

la raison pour laquelle j'ai utilisé l'expansion retardée dans le test sans en utiliser !'s est parce qu'il affecte toujours la façon dont le set fonctionne et les batchs que je teste cette pour tous ont retardé l'expansion.

Merci pour l'aide les gars: o)

PS j'ai essayé d'utiliser le même nom de variable locale et externe mais cela a enfreint le code. D'où les 2 noms utilisés.

2
répondu Aaron Lowe 2016-04-01 14:53:43