Vous semblez être bien conscient de expansion retardée puisque vous l'utilisez correctement la plupart du temps.
Cependant, ce que vous avez dans votre code, je l'appelle généralement des variables imbriquées, parce qu'il n'y a pas de véritables tableaux dans les scripts batch puisque chaque élément de tableau n'est rien d'autre qu'une variable scalaire individuelle ( pems[0]
, pems[1]
, pems[2]
) ; on peut donc parler de pseudo-raies.
Bref, quelque chose comme echo !pems[%selectedPem%]!
peut être correctement développée, à moins qu'elle ne soit placée dans une ligne ou un bloc de code dans lequel selectedPem
est mis à jour avant, parce qu'alors nous aurions besoin d'une expansion retardée pour selectedPem
également. echo !pems[!selectedPem!]!
ne fonctionne pas, car il essaie d'étendre les variables pems[
y ]
et selectedPem
est interprété comme une chaîne littérale.
Avant d'aller plus loin, revenons d'abord à echo !pems[%selectedPem%]!
: pourquoi est-ce que c'est extensible ? Eh bien, l'astuce est que nous avons deux phases d'expansion ici, l'expansion normale ou immédiate ( %
), suivie par l'expansion retardée ( !
). L'important est la séquence : la variable intérieure des variables imbriquées (donc l'indice du tableau) doit être dépensée avant la variable extérieure (donc l'élément du tableau). Quelque chose comme echo %pems[!selectedPem!]%
ne peut pas être développé correctement, car il n'y a (très probablement) aucune variable nommée pems[!selectedPem!]
et après l'avoir étendu à une chaîne de caractères vide, les deux !
disparaissent et la phase d'expansion retardée ne les voit donc jamais.
Allons maintenant un peu plus loin : pour développer quelque chose de similaire à echo !pems[%selectedPem%]!
à l'intérieur d'une ligne ou d'un bloc de code qui met également à jour selectedPem
nous devons éviter une expansion immédiate. Nous avons déjà appris que l'expansion différée ne peut pas être imbriquée, mais il existe d'autres expansions :
- Le site
call
commande introduit une autre phase d'expansion après l'expansion retardée, qui gère à nouveau %
-La séquence complète est donc l'expansion immédiate, l'expansion différée et une autre %
-Expansion. Ignorant la première, utilisons les deux dernières de manière à ce que la variable intérieure des variables imbriquées soit développée avant la variable extérieure, c'est-à-dire : call echo %%pems[!selectedPem!]%%
. Pour sauter la phase d'expansion immédiate, il suffit de doubler la valeur du %
qui sont remplacés par un signe littéral chacun, de sorte que nous avons echo %pems[!selectedPem!]%
après une expansion immédiate. L'étape suivante est l'expansion différée, puis la dite suivante %
-Expansion.
Vous devez prendre note que le call
est assez lente, de sorte qu'une utilisation intensive pourrait réduire considérablement les performances globales de votre script.
- Expansion de
for
boucle Les variables se produisent après l'expansion immédiate, mais avant l'expansion différée. Enveloppons donc un for
boucle autour qui itère une seule fois et renvoie la valeur de selectedPem
comme ceci : for %%Z in (!selectedPem!) do echo !pems[%%Z]!
. Cela fonctionne, car for
n'accède pas au système de fichiers, sauf si un joker *
ou ?
apparaît, qui ne devrait pas être utilisé dans les noms de variables ou les index de (pseudo-)tableaux de toute façon.
Au lieu d'un for
boucle, for /F
pourrait également être utilisé : for /F %%Z in ("!selectedPem!") do echo !pems[%%Z]!
(il n'y a pas de chaîne d'options comme "delims="
nécessaire en cas de selectedPem
est censé ne contenir qu'un numéro d'index).
A for /L
boucle pourrait également être utilisé (pour les index numériques, bien sûr) : for /L %%Z in (!selectedPem!,1,!selectedPem!) do echo !pems[%%Z]!
.
- Expansion implicite établie par le
set /A
commande ce qui signifie que ni l'un ni l'autre %
ni !
est nécessaire pour lire les variables, peut aussi être utilisée, mais seulement si l'élément du tableau contient une valeur numérique (notez que la fonction /A
représente l'arithmétique). Comme il s'agit d'une fonctionnalité spécifique à set /A
ce type d'expansion se produit pendant l'exécution de la commande, qui se produit à son tour après une expansion retardée. Donc on peut utiliser ça comme ça : set /A "pem=pems[!selectedPem!]" & echo !pem!
.
- Par souci d'exhaustivité, voici une autre façon de procéder :
set /A
lorsqu'il est exécuté dans cmd
plutôt que dans le contexte d'un lot, affiche le (dernier) résultat sur la console ; étant donné que cela constitue le numéro d'index, nous pourrions capturer cela par for /F
et développer l'élément du tableau comme ceci : for /F %%Z in ('set /A "selectedPem"') do echo !pems[%%Z]!
. set /A
est exécuté dans une nouvelle cmd
instance par for /F
Cette approche n'est donc pas la plus rapide, bien entendu.
Il existe un article très complet sur ce sujet que vous devriez lire en détail : Tableaux, listes chaînées et autres structures de données dans cmd.exe (batch) script. .
Pour l'analyse des lignes de commande et des scripts ainsi que l'expansion des variables en général, référez-vous à ce fil de discussion génial : Comment l'interpréteur de commandes Windows (CMD.EXE) analyse-t-il les scripts ?
Maintenant, jetons un coup d'oeil à votre code. Il y a plusieurs problèmes :
- utiliser
cd /D
au lieu de cd
afin de changer également le variateur si nécessaire ; d'ailleurs, la variable intermédiaire dir
n'est pas nécessaire (je recommande de ne pas utiliser de noms de variables qui correspondent à des commandes internes ou externes pour des raisons de lisibilité), utilisez simplement cd
sur le chemin immédiatement ;
- vous avez omis d'utiliser l'expansion retardée en ligne
set pems[%pemI%]=%%~nxp
il faut lire set pems[!pemI!]=%%~nxp
como pemI
est mis à jour dans l'environnement for
boucle ;
- vous avez soit besoin d'une expansion retardée en ligne
set /a pemI=%pemI%+1
aussi, ou vous utilisez l'expansion implicite de variable de set /A
Así que set /A pemI=pemI+1
fonctionnerait ; on peut même simplifier davantage : set /A pemI+=1
ce qui est totalement équivalent ;
- J'utiliserais la comparaison insensible à la casse, en particulier lorsqu'il s'agit d'une saisie de l'utilisateur, comme dans le cas de votre vérification de la présence de
Q
qui serait if /I "!selectedPem!"=="q"
;
- Nous arrivons maintenant à une ligne qui nécessite ce que nous avons appris ci-dessus :
ECHO !pems[%selectedPem%]!
doit devenir call echo %%pems[!selectedPem!]%%
; une autre façon d'utiliser for
est également inséré dans un commentaire ( rem
) ;
- puis il y a une autre ligne avec le même problème :
set privatekey=!pems[%selectedPem%]!
doit devenir call set privatekey=%%pems[!selectedPem!]%%
(ou l'approche basée sur for
aussi) ;
- une fois de plus vous avez manqué l'utilisation de l'expansion retardée, cette fois en ligne
ECHO You chose %privatekey%
qui devrait se lire echo You chose !privatekey!
;
- enfin j'ai amélioré la citation de votre code, en particulier celle de
set
qui devraient plutôt être écrites comme set "VAR=Value"
La valeur elle-même est protégée si elle contient des caractères spéciaux, mais les guillemets ne font pas partie de la valeur, ce qui peut être particulièrement gênant pour la contaténation ;
Voici donc le code corrigé (avec tous vos originaux rem
remarques supprimées) :
@echo off
setlocal EnableDelayedExpansion
cd /D "%~dp0"
echo Performing initial search of private and public keys...
set "pemI=0"
set "keyI=0"
for %%p in (*.pem) do (
set "pems[!pemI!]=%%~nxp"
set /A "pemI+=1"
)
set /A "totalPems=pemI-1"
if defined pems[0] (
echo PEM Files Found:
for /L %%p in (0,1,%totalPems%) do (
echo %%p^) !pems[%%p]!
)
set /P selectedPem="Enter a number or Q: "
if /I "!selectedPem!"=="q" (
echo Skipping private key selection.
) else (
echo !selectedPem!
echo %pems[0]%
call echo %%pems[!selectedPem!]%%
rem for %%Z in (!selectedPem!) do echo !pems[%%Z]!
call set "privatekey=%%pems[!selectedPem!]%%"
rem for %%Z in (!selectedPem!) do set "privatekey=!pems[%%Z]!"
echo You chose !privatekey!
)
)
Je dois admettre que je n'ai pas vérifié la logique de votre script en détail cependant.