你似乎很清楚
delayed expansion
因为你大部分时间都在正确使用它。
然而,我通常将代码中的内容称为嵌套变量,因为批处理脚本中没有真正的数组,因为每个数组元素都只是一个单独的标量变量(
pems[0]
,
pems[1]
,
pems[2]
等);所以我们也可以将类似的内容称为伪数组。
不管怎么说
echo !pems[%selectedPem%]!
可以正确展开,除非它放在
selectedPem
在之前更新,因为这样我们就需要延迟扩展
选定PEM
也
echo !pems[!selectedPem!]!
不起作用,因为它试图扩展变量
pems[
和
]
和
选定PEM
被解释为文字字符串。
在继续之前,让我们先回到
回响PEM[%selectedPem%]!
:为什么这是可扩展的?诀窍是我们有两个扩张阶段,正常扩张或立即扩张(
%
),然后是延迟扩展(
!
)。重要的是顺序:嵌套变量的内部变量(因此数组索引)必须在外部变量(因此数组元素)之前展开。差不多
echo %pems[!selectedPem!]%
无法正确展开,因为(很可能)没有名为
pems[!selectedPem!]
,并将其扩展为空字符串后
!
消失,因此延迟扩展阶段永远看不到它们。
现在让我们更进一步:扩展类似于
回响PEM[%selectedPem%]!
在代码行或代码块内部也会更新
选定PEM
,我们必须避免立即扩张。我们已经了解到延迟扩展不能嵌套,但还有一些其他扩展:
-
这个
call
command
在延迟扩展之后引入另一个扩展阶段,该阶段再次处理
%
-标志;所以完整的顺序是立即扩张,延迟扩张和另一种扩张
%
-扩展。忽略第一个,让我们以一种方式利用后两个,即嵌套变量中的内部变量在外部变量之前展开,这意味着:
call echo %%pems[!selectedPem!]%%
.为了跳过即时扩展阶段,我们只需将
%
符号,每一个都被一个字面符号所取代,所以我们有
回显%pems[!selectedPem!]%
立即膨胀后。下一步是延迟扩张,然后是下一步
%
-扩展。
你应该注意到
呼叫
方法非常慢,因此大量使用可能会大幅降低脚本的整体性能。
-
扩张
for
loop
变量发生在立即展开之后,但在延迟展开之前。让我们来总结一下
对于
循环,只迭代一次并返回
选定PEM
,就像这样:
for %%Z in (!selectedPem!) do echo !pems[%%Z]!
.这很有效,因为
对于
除非有通配符,否则不会访问文件系统
*
或
?
出现,但无论如何都不应在变量名或(伪)数组索引中使用。
而不是标准
对于
环
for /F
也可用于:
for /F %%Z in ("!selectedPem!") do echo !pems[%%Z]!
(没有类似字符串的选项。)
"delims="
在情况下需要
选定PEM
预计只包含一个索引号)。
A.
for /L
loop
也可以使用(当然,对于数字索引):
for /L %%Z in (!selectedPem!,1,!selectedPem!) do echo !pems[%%Z]!
.
-
由
set /A
command
,这意味着
%
也没有
!
是读取变量所必需的,也可以使用,但仅当数组元素包含数值时(请注意
/A
代表算术)。因为这是特定于
设置/A
,这种扩展发生在命令执行期间,而命令执行又发生在延迟扩展之后。所以我们可以这样使用:
set /A "pem=pems[!selectedPem!]" & echo !pem!
.
-
为了完整起见,还有一种方法:
设置/A
,在中执行时
cmd
而不是在批处理上下文中,在控制台上输出(最后一个)结果;考虑到这构成了索引号,我们可以通过
for /F
然后像这样展开数组元素:
for /F %%Z in ('set /A "selectedPem"') do echo !pems[%%Z]!
.
设置/A
以新的方式执行
命令
实例依据
对于/F
所以这种方法当然不是最快的。
关于这一主题,有一篇很好且全面的帖子,你应该仔细阅读:
Arrays, linked lists and other data structures in cmd.exe (batch) script
.
有关命令行和批处理脚本的解析以及变量扩展的一般信息,请参阅以下内容:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
现在让我们看看您的代码。有几个问题:
-
使用
cd /D
而不是
cd
以便在必要时更换驱动器;顺便说一下,中间变量
dir
没有必要(为了可读性,我建议不要使用与内部或外部命令相等的变量名),只需使用
光盘
立即在道路上;
-
你错过了在队列中使用延迟扩展
set pems[%pemI%]=%%~nxp
,应该是
set pems[!pemI!]=%%~nxp
像
pemI
在周围环境中更新
对于
环
-
你要么需要延迟扩张
set /a pemI=%pemI%+1
也可以使用
设置/A
所以
set /A pemI=pemI+1
会起作用;然而,这甚至可以更加简化:
set /A pemI+=1
,这是完全等价的;
-
我会使用不区分大小写的比较,尤其是当涉及到用户输入时,比如检查
Q
,也就是
if /I "!selectedPem!"=="q"
;
-
现在,我们来到了一条需要我们以上所学知识的路线:
ECHO !pems[%selectedPem%]!
需要成为
呼叫echo%%pems[!selectedPem!]%%
; 另一种使用
对于
也被插入到评论中(
rem
);
-
还有另一条线路也有同样的问题:
set privatekey=!pems[%selectedPem%]!
需要成为
call set privatekey=%%pems[!selectedPem!]%%
(或基于
对于
也是);
-
你又一次错过了延迟扩展,这次是排队
ECHO You chose %privatekey%
,应为
echo You chose !privatekey!
;
-
最后,我改进了代码的引用,特别是
set
命令,最好这样写
set "VAR=Value"
,因此,任何不可见的尾随空格都不会成为值的一部分,如果值包含特殊字符,则该值本身也会受到保护,但引号不会成为值的一部分,这可能会特别影响连续性;
下面是固定代码(包括所有原始代码
雷姆
备注(已删除):
@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!
)
)
我得承认我没有详细检查你剧本的逻辑。