如何使用函数参数中的数组索引打印数组的值?

问题描述 投票:0回答:1

我正在使用三个功能。一是获取驱动器列表:

REM list the drives
:list_disk
ECHO List of drives

set n=0
for /f "skip=1 delims=" %%a in ('wmic logicaldisk get DeviceID^') do (
    set nom[!n!]=%%a
    set /A n+=1
)
set /A "N=%n%/2"
FOR /L %%i IN (0,1,%N%) DO (
    echo !nom[%%i]!
    echo/
)
EXIT /B 0

第二个是建议用户选择在下一个函数中应处理哪些驱动器:

REM choice of drives
:choix nom
echo Choice
FOR /L %%i IN (0,1,%N%) DO (
    echo Do you want to raise the drive !nom[%%i]!
    echo (y/n^) ?

    SET c=n
    SET /P c=
    if !c!==y call :HASH i
)

EXIT /B 0

最后一个使用数组的索引来处理所选驱动器:

REM fingerprinting
:HASH
ECHO Fingerprinting in progress ...
echo !nom[%%i]!

ECHO progam integration fingerprint :

EXIT /B 0

问题在于最后一个

echo !nom[%%i]!
,它没有按预期工作。

为什么不打印选择的驱动器?

arrays for-loop batch-file set echo
1个回答
0
投票

主要问题是通过使用

i
而不是
i
将字符串
HASH
而不是循环变量
if !c!==y call :HASH i
的值传递给子例程
if !c!==y call :HASH %%i
并使用
 引用循环循环变量的值引起的echo !nom[%%i]!
在子例程执行的上下文中根本不存在,而不是通过
echo !nom[%1]!
传递给子例程的值。

但是此代码还存在其他几个问题,例如由于驱动器索引错误而忽略最后一个驱动器或使用

set /p
,尽管使用
choice
在这里肯定会更好,因为更安全。

还建议在批处理文件中引用具有众所周知路径的可执行文件及其完全限定的文件名,从而使批处理文件的执行速度更快,因为

cmd.exe
不需要使用环境变量
PATH
和搜索可执行文件
PATHEXT
,因此可以避免在执行批处理文件期间进行大量文件系统访问。

更好的代码是:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem list the drives
:list_disk
echo List of drives
echo(
set n=-1
for /F "tokens=2 delims==:" %%i in ('%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET DeviceID /VALUE') do (
    set /A n+=1
    set nom[!n!]=%%i
)
for /L %%i IN (0,1,%n%) do echo !nom[%%i]!:

rem choice of drives
:choix nom
echo(
echo Choice
echo(
for /L %%i in (0,1,%n%) do (
    %SystemRoot%\System32\choice.exe /C NY /N /M "Do you want to raise the drive !nom[%%i]!: (Y/N)?"
    if errorlevel 2 call :HASH %%i
)
exit /B 0

rem fingerprinting
:HASH
echo(
echo Fingerprinting in progress for drive !nom[%1]!: ...
rem Call of the command to generate the fingerprint for drive !nom[%1]!
echo program integration fingerprint:
echo(
exit /B 0

第一个 FOR 循环现在仅将不带冒号的驱动器号分配给具有

name[x]
的环境变量,其中
x
的范围为 0 到
n
,例如
0
3
在四个驱动器输出上
wmic

使用

wmic
选项
/VALUE
for /F
选项
tokens=2
delims==:
避免了
wmic
错误解析
for
的UTF-16 Little Endian输出的问题。命令
for
0D 00 0A 00
(UTF-16 LE 编码的回车+换行)错误地解释为
0D 0D 0A
(回车+回车+换行)。这个错误的 Unicode 文本解析并不重要,因为仅从
i
的输出分配给循环变量
DeviceID=
:
之间的驱动器号。
因此,分配给 

wmic

的已处理行数和创建的环境变量数是正确的,不再需要除以 2。

n
现在是定义带有驱动器盘符的环境变量时使用的最后一个索引号。
选择的 

FOR

循环现在使用命令 CHOICE 来提示用户选择是/否。对于法语版本,命令行中的字母 n 可以替换为

Y
,即使用
O
/C NO
。有关更多详细信息,请参阅我的答案:
如何阻止 Windows 命令解释器在用户输入不正确时退出批处理文件执行?
使用

(O/N)

代替

mountvol.exe
的另一种解决方案在从内部版本 22572 开始的 Windows 11 中不再可用:
wmic.exe

在这种情况下,环境变量是使用驱动器号和冒号定义的,因为冒号已添加到第 
@echo off setlocal EnableExtensions EnableDelayedExpansion rem list the drives :list_disk echo List of drives echo( set n=-1 for /F "delims=: " %%i in ('%SystemRoot%\System32\mountvol.exe ^| %SystemRoot%\System32\find.exe ":\" ^| %SystemRoot%\System32\sort.exe') do ( set /A n+=1 set nom[!n!]=%%i: ) for /L %%i IN (0,1,%n%) do echo !nom[%%i]! rem choice of drives :choix nom echo( echo Choice echo( for /L %%i in (0,1,%n%) do ( %SystemRoot%\System32\choice.exe /C NY /N /M "Do you want to raise the drive !nom[%%i]! (Y/N)?" if errorlevel 2 call :HASH %%i ) exit /B 0 rem fingerprinting :HASH echo( echo Fingerprinting in progress for drive !nom[%1]! ... rem Call of the command to generate the fingerprint for drive !nom[%1]! echo program integration fingerprint: echo( exit /B 0

行。也可以使用

set nom[!n!]=%%i:
代替
delims=\ 
delims=: 
来获取使用驱动器盘符和冒号定义的环境变量。
使用 

set nom[!n!]=%%i

获取带冒号的驱动器并将其分配给环境变量的另一个解决方案是:

fsutil.exe

可以省略
for /F "tokens=1*" %%i in ('%SystemRoot%\System32\fsutil.exe fsinfo drives') do for %%k in (%%j) do for /F "delims=\" %%l in ("%%k") do (
    set /A n+=1
    set nom[!n!]=%%l
)

,并将

for /F "delims=\" %%l in ("%%k") do
更改为
set nom[!n!]=%%l
,以获取带有冒号并将反斜杠分配给环境变量的驱动器,即
set nom[!n!]=%%k
C:\
,...而不是
D:\
C:
,...
获取驱动器的第三个解决方案的其他行与第二个解决方案中的相同,带有 

D:

注意:

使用 mountvol.exe 的解决方案期望输出如下:

fsutil.exe

这是英文 Windows 上的输出。如果第一个输出驱动器中有多个空格分隔的单词最终以 
Drives: C:\ D:\ R:\

而不是

:
结尾,最好在第一个
Drives:
命令中使用
"tokens=1* delims=:"
而不是仅使用
"tokens=1*"
来忽略第一个左侧的字符串在
for /F
的输出中使用冒号,而不是保留第一个空格,并使用第二个
fsutil.exe
命令处理该行的剩余部分,并使用空格分隔的驱动器。
要了解所使用的命令及其工作原理,请打开

命令提示符

窗口,执行以下命令,并完整、仔细地阅读每个命令显示的帮助页面。

    for
  • call /?
  • choice /?
  • echo /?
  • ...未显式使用,而是通过
    endlocal /?
     隐式运行
    
  • cmd.exe
  • exit /?
  • find /?
  • for /?
  • fsutil /?
  • fsutil fsinfo /?
  • mountvol /?
  • rem /?
  • set /?
  • setlocal /?
  • sort /?
  • wmic /?
  • wmic logicaldisk /?
  • 
        
© www.soinside.com 2019 - 2024. All rights reserved.