Home > other >  How do I print the value of an array with the index of the array in argument of my function?
How do I print the value of an array with the index of the array in argument of my function?

Time:07-26

I am using three functions. One is getting the list of drives:

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

The second is proposing to the user to choose which drives should be processed in the next function:

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

And the last one uses the index of the array to process the chosen drive:

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

ECHO progam integration fingerprint :

EXIT /B 0

The problem is the last echo !nom[%%i]! which doesn't work as expected.

Why does it not print which drive is selected?

CodePudding user response:

The main problem is caused by passing the string i instead of the value of loop variable i to the subroutine HASH by using if !c!==y call :HASH i instead of if !c!==y call :HASH %%i and referencing the value of the loop loop variable with echo !nom[%%i]! not existing at all in the context of the subroutine execution instead of the value passed to the subroutine with echo !nom[%1]!.

But there are several other problems with this code like ignoring the last drive because of indexing the drives wrong or usage of set /p although using choice would be definitely better here as more fail-safe and secure.

It is also advisable to reference executables with well-known path in batch files with their fully qualified file names making the execution of the batch file faster as cmd.exe does not need to search for the executables using the environment variables PATH and PATHEXT and so avoiding lots of file system accesses during execution of the batch file.

A better code is:

@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 WinHASH integration fingerprint:
echo/
exit /B 0

The first FOR loop assigns now only the drive letter without colon to the environment variable with name[x] whereby x is in range 0 to n, for example 0 to 3 on four drives output by wmic.

The usage of wmic option /VALUE and the for /F options tokens=2 and delims==: avoids the problem with wrong parsed UTF-16 Little Endian output of wmic by for. The command for interprets 0D 00 0A 00 (UTF-16 LE encoded carriage return line-feed) wrong as 0D 0D 0A (carriage return carriage return line-feed). This wrong Unicode text parsing does not matter because of assigning to the loop variable i only the drive letter between DeviceID= and : from the output of wmic.

Therefore the number of processed lines and created environment variables assigned to n is correct and no division by two is necessary anymore. n is now the last index number used on definition of an environment variable with a drive letter.

The FOR loop for the choice uses now the command CHOICE to prompt the user for the Yes/No choice. The letters Y in the command line can be replaced by O for the French version, i.e. using /C NO and (O/N). For more details see my answer on How to stop Windows command interpreter from quitting batch file execution on an incorrect user input?

Another solution using mountvol.exe instead of wmic.exe which is not available anymore in Windows 11 starting with build 22572:

@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 WinHASH integration fingerprint:
echo/
exit /B 0

In this case the environment variables are defined with drive letter and colon as the colon is already added on line set nom[!n!]=%%i:. It would be also possible to use delims=\ instead of delims=: and set nom[!n!]=%%i to get the environment variables defined with drive letter and colon.

Another solution using fsutil.exe to get the drives with colon for assigning them to the environment variables is:

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 could be omitted and set nom[!n!]=%%l changed to set nom[!n!]=%%k to get the drives with colon and with the backslash assigned to the environment variables, i.e. C:\, D:\, ... instead of C:, D:, ...

The other lines of this third solution getting the drives are the same as in second solution with mountvol.exe.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • choice /?
  • echo /?
  • endlocal /? ... not used explicitly, but run implicitly by cmd.exe
  • exit /?
  • find /?
  • for /?
  • fsutil /?
  • fsutil fsinfo /?
  • mountvol /?
  • rem /?
  • set /?
  • setlocal /?
  • sort /?
  • wmic /?
  • wmic logicaldisk /?
  • wmic logicaldisk get /?
  • Related