I have come up with a batch script, through some Googling and analysis on batch scripts, for checking if the package I mention in user prompt exists in system and get its version if it does. Here it is in its most possible final version:
@echo off && setlocal EnableDelayedExpansion
set "output_cnt=0"
set /p "pkg=Package? "
for /f "delims=" %%a in ('npm -v 2^>nul') do @set "npmV=%%a"
if defined npmV (echo NPM Version: %npmV%) else (echo NPM isn't installed)
for /f "delims=" %%b in ('node -v 2^>nul') do @set "nodeV=%%b"
if defined nodeV (echo Node Version: %nodeV%) else (echo Node isn't installed)
for /f "delims=" %%c in ('npm list -g %pkg% 2^>nul') do (
set /a output_cnt =1
set "pkgV[!output_cnt!]=%%c"
)
if defined pkgV (for /l %%n in (1 1 !output_cnt!) do echo !pkg! Version: !pkgV[%%n]!) else (echo %pkg% isn't installed)
setlocal DisableDelayedExpansion && endlocal && pause
Now when I run this script, it does check properly whether Node and NPM are installed and gets their version accurately, but when I pass any package name to the user prompt (e.g. cowsay, and this package is installed, of that I am sure), it always says <package> isn't installed
(as in cowsay isn't installed
).
As you can see I am trying to capture full output of npm list -g <package>
with multiple lines through array, but it clearly screws up.
Can anyone assist in figuring out what's wrong and get what I want?
CodePudding user response:
Welcome to batch; arrays aren't real!*
Instead, you've got a collection of variables that all simply happen to start with pkgV[
that you're able to iterate over. So while %pkgV[1]%
, %pkgV[2]%
, etc. are all defined, %pkgV%
by itself isn't because that particular variable was never set.
However, since you'll always have a %pkgV[1]%
if any valid packages have been provided, you can check that pkgV[1]
is defined and go from there. (Alternately, you can simply check that %output_cnt%
is greater than 0.)
if defined pkgV[1] (for /l %%n in (1 1 !output_cnt!) do echo !pkg! Version: !pkgV[%%n]!) else (echo %pkg% isn't installed)
* - At least, not in the way that other languages do arrays.
CodePudding user response:
Why do you use a (pseudo-)array after all? Why not simply doing all in a single loop?
I see two possible code portions to replace the for /f %%c
loop and the subsequent if defined pkgV
condition (which actually is the faulty code fragment as explained in SomethingDark's answer) with:
Use a flag-style variable that indicates whether
npm list
returned any items:@echo off & setlocal EnableExtensions DisableDelayedExpansion set "output_cnt=0" set /p "pkg=Package? " for /f "delims=" %%a in ('npm -v 2^>nul') do @set "npmV=%%a" if defined npmV (echo NPM Version: %npmV%) else (echo NPM isn't installed) for /f "delims=" %%b in ('node -v 2^>nul') do @set "nodeV=%%b" if defined nodeV (echo Node Version: %nodeV%) else (echo Node isn't installed) set "FLAG=" for /f "delims=" %%c in ('npm list -g %pkg% 2^>nul') do ( set "FLAG=#" & echo !pkg! Version: %%c ) if not defined FLAG echo %pkg% isn't installed pause
Detect the exit code of the
for /f %%c
loop by conditional execution, which is set to1
when the loop doesn't iterate:@echo off & setlocal EnableExtensions DisableDelayedExpansion set "output_cnt=0" set /p "pkg=Package? " for /f "delims=" %%a in ('npm -v 2^>nul') do @set "npmV=%%a" if defined npmV (echo NPM Version: %npmV%) else (echo NPM isn't installed) for /f "delims=" %%b in ('node -v 2^>nul') do @set "nodeV=%%b" if defined nodeV (echo Node Version: %nodeV%) else (echo Node isn't installed) ( for /f "delims=" %%c in ('npm list -g %pkg% 2^>nul') do ( echo !pkg! Version: %%c ) ) || echo %pkg% isn't installed pause
N. B.:
By the way, the command sequence setlocal DisableDelayedExpansion && endlocal
at the end doesn't make any sense at all, since the state afterwards is just the same as without it.
If the intention was to surely have delayed expansion disabled at the pause
command, you should have replaced your initial line with @echo off & setlocal EnableExtensions DisableDelayedExpansion
and have inserted the line setlocal EnableDelayedExpansion
before the for /f %%c
loop in your original code.
CodePudding user response:
If there will only be one installed version of any input package, then perhaps this would work for you:
@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "nodeV="
For %%G In ("node.js") Do For /F %%H In (
'"%%~$PATH:%%G" -v') Do Set "nodeV=%%H"
If Defined nodeV (Echo Node Version: %nodeV%
) Else Echo node.js is not in your %%PATH%%
Set "npmV="
For %%G In ("npm.cmd") Do For /F %%H In (
'"%%~$PATH:%%G" -v') Do Set "npmV=%%H"
If Defined npmV (Echo NPM Version: %npmV%
) Else (Echo npm.cmd is not in your %%PATH%%
Echo Press any key to exit ...
Pause 1>NUL
Exit /B)
:GetPkg
Set "pkg="
Set /P "pkg=Package? "
If Not Defined pkg GoTo GetPkg
Set "pkgV="
For /F "Tokens=2 Delims=@" %%G In (
'npm.cmd list "%pkg%" -g 2^>NUL
^| %SystemRoot%\System32\find.exe "@"'
) Do Set "pkgV=%%G"
If Defined pkgV (Echo %pkg% Version: %pkgV%
) Else Echo %pkg% is not globally installed
Pause
EndLocal
GoTo :EOF
However, if there could be multiple installed versions of your input package, as implied by your code, then this modification may prove more useful:
@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "nodeV="
For %%G In ("node.js") Do For /F %%H In (
'"%%~$PATH:%%G" -v') Do Set "nodeV=%%H"
If Defined nodeV (Echo Node Version: %nodeV%
) Else Echo node.js is not in your %%PATH%%
Set "npmV="
For %%G In ("npm.cmd") Do For /F %%H In (
'"%%~$PATH:%%G" -v') Do Set "npmV=%%H"
If Defined npmV (Echo NPM Version: %npmV%
) Else (Echo npm.cmd is not in your %%PATH%%
Echo Press any key to exit ...
Pause 1>NUL
Exit /B)
:GetPkg
Set "pkg="
Set /P "pkg=Package? "
If Not Defined pkg GoTo GetPkg
For /F "Delims==" %%G In ('"(Set pkgV[) 2>NUL"'
) Do Set "%%G="
Set "output_cnt=0"
For /F "Tokens=2 Delims=@" %%G In (
'npm.cmd list %pkg% -g 2^>NUL
^| %SystemRoot%\System32\find.exe "@"'
) Do (Set /A output_cnt = 1
SetLocal EnableDelayedExpansion
For %%H In (!output_cnt!) Do (EndLocal
Set "pkgV[%%H]=%%G"))
If %output_cnt GEq 1 (
For /F "Tokens=2,* Delims=[]=" %%G In (
'"(Set pkgV[) 2>NUL"'
) Do Echo %pkg% version %%G: %%H
) Else Echo %pkg% is not globally installed
Pause
EndLocal
GoTo :EOF
Please note, that none of the above code has been tested at all, if there are obvious typos, or errors, please let me know, and I'll take a look at it later.