Error: "|" was unexpected at this time batch script - batch-file

When I run this script, I receive
| was unexpected at this time.
This is code:
#ECHO Off
REM Mapeo de unidad U, path de usuario
net use u: \\server\usuarios\%username%
pause
REM ***** Description group ****
for /f %%i in ('net user %username% /domain | find /i /c Group') do set RESULT=%%i
echo %RESULT%
pause
In for sentence, i use " and ', but I still got error.

The condition inside the for must be parsed by the batch parser before it can pass it to the IN() clause as an executable command and since the pipe is a special character in DOS, you need to use escape character(^) before pipe to preserve it during the initial batch parsing, as shown below:
for /f %%i in ('net user %username% /domain ^| find /i /c Group') do set RESULT=%%i

You need to escape the pipe char inside for command. It should be ^|

Related

How to escape spaces while Set a parameter in Bat file

I'm trying to do this:
#echo off
Set ^"Processes=Sample.exe ^
The Sample Program.exe^"
But The Sample Program.exe acting as three separate files The Sample and Program.exe.
What is the procedure to escape the spaces?
Full code:
for %%a in (%Processes%) Do (
for /f %%b in ('tasklist /NH /FI "imagename eq %%a"') Do (
if [%%b]==[%%a] (
echo %%b is running
Color 0C
echo Killing %%b ...
Taskkill /f /im "%%b"
) else (
Color 0A
echo %%a is not running
)
)
)
pause & exit
Something along this line?
for /F "tokens=1* delims=," %%b
A simple demonstration code for what I think you want to achieve is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set Processes="cmd.exe Windows Command Processor" "cscript.exe Console Based Script Host"
for %%G in (%Processes%) do for /F "eol=| tokens=1*" %%H in (%%G) do (
echo File name is: %%H
echo Process name: %%I
)
endlocal
The output of this batch file on execution is:
File name is: cmd.exe
Process name: Windows Command Processor
File name is: cscript.exe
Process name: Console Based Script Host
So the environment variable Processes is defined with multiple strings enclosed in double quotes. Each string has first the file name of an executable without path and separated by a space (could be also a different character) the process name or whatever is needed to be associated with the executable file name which should not contain ? or *.
The outer FOR loop assigns one after the other a string enclosed in double quotes to the specified loop variable G.
The inner FOR loop splits up the string assigned currently to loop variable G into two substrings and assigns the first normal space/horizontal tab delimited string to specified loop variable H and everything else after one or more spaces/tabs to next but one loop variable I.
The executable file name assigned to H and the associated string assigned to I can be used for whatever purpose in the command block of the inner FOR loop.
This method applied to what the batch file should do:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set Processes="notepad.exe Windows Notpad" "cscript.exe Console Based Script Host"
for %%G in (%Processes%) do for /F "eol=| tokens=1*" %%H in (%%G) do (
%SystemRoot%\System32\tasklist.exe /NH /FI "imagename eq %%H" 2>nul | %SystemRoot%\System32\find.exe /I "%%H" >nul
if not errorlevel 1 (
echo %%I is running.
color 0C
echo Terminating %%I ...
%SystemRoot%\System32\taskkill.exe /IM "%%H" >nul
) else (
color 0A
echo %%I is not running.
)
)
color
endlocal
The option /F to force a brutal kill of the running process by the operating system is removed from this code. The most applications gracefully terminate itself on TASKKILL sending the WM_CLOSE message to the running application.
Please note that closing all instances of script interpreters like cmd.exe, cscript.exe, wscript.exe, powershell.exe as done by the TASKKILL with just image name passed as argument is in general not good. For example the cmd.exe instance currently processing the batch file would be terminated also on using this batch code to terminate a cmd.exe running with a different console window parallel.
Example for the unusual cases of executable file names with one or more spaces with using | as delimiter between file name and associated string which no file name can contain ever:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set Processes="notepad.exe|Windows Notpad" "cscript.exe|Console Based Script Host" "show time.exe|Show Time Information"
for %%G in (%Processes%) do for /F "eol=| tokens=1* delims=|" %%H in (%%G) do (
%SystemRoot%\System32\tasklist.exe /NH /FI "imagename eq %%H" 2>nul | %SystemRoot%\System32\find.exe /I "%%H" >nul
if not errorlevel 1 (
echo %%I is running.
color 0C
echo Terminating %%I ...
%SystemRoot%\System32\taskkill.exe /IM "%%H" >nul
) else (
color 0A
echo %%I is not running.
)
)
color
endlocal
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.
echo /?
endlocal /?
find /?
for /?
setlocal /?
taskkill /?
tasklist /?
Example based upon my comment:
Set ^"Processes="Sample.exe"^
"The Sample Program.exe"^"
For %%G In (%Processes%) Do Echo %%G
Pause
Obviously when using %%G in your /Filter, you'd just remove those doublequotes, i.e. %SystemRoot%\System32\tasklist.exe /NH /Fi "ImageName Eq %%~G"
Please note that the leading space before any line which begins with a doublequote is required

How do you put quotes around the variable of a For loop in batch?

I am working on a batch script that will take a list of server, loop through them, find every service on each server that starts with a certain value, and query that service. However, given that service names can be created with spaces, I need to be able to put quotes around the for variable. What would be the best way to do this?
I've tried various methods of putting escape characters before and after the variable. I've also attempted setting the loop variable to a separate variable.
#ECHO off
ECHO Please list servers to query.
SET list=
SET /P list=Server Names:
FOR %%a IN (%list%) DO (
FOR /F "Skip=1 Delims-" %%b IN ('wmic service where "name like 'ADOBE%%'" get Name ^| findstr /r /v "^$"') DO (
ECHO %%b
sc \\%%a query ^"%%b^"
)
)
pause
GOTO :eof
The output show the service name of any service that starts with "ADOBE" on one of the servers entered in %list%.
What I'm getting is "EnumQueryServiceStatus:OpenService FAILED 1060:
The specified service does not exist as an installed service."
When I allow the script to echo, I see this:
HO AdobeARMservice
" \[servername] query "AdobeARMservice
The main issue is due to a spaces and carriage return characters in the output of wmic. If you add quotes around %%b in the line with echo in your code you'll see that the closing quote is missing from the output.
Working code:
#echo off
setlocal enabledelayedexpansion
FOR /F "Skip=1 Delims=" %%b IN ('wmic service where "name like 'ADOBE%%'" get Name ^| findstr /r /v "^$"') DO (
for /f "delims=" %%c in ("%%b") do ( rem this will get rid of CR character
set d=%%c
:loop
if "!d:~-1!"==" " ( rem here we'll remove the trailing spaces
set d=!d:~0,-1!
goto :loop
)
echo "%d%"
sc query "%d%"
)
)

parsing the output of a command with a complex path in batch

I have a Windows 8 batch file where I'm trying to parse the output of a command to set a variable. The following works fine if the path inset frob=c:\path_to_frob\frob.exe contains no spaces:
for /f "tokens=5" %%i in ('%frob% -l ^| findstr "flux capacitor at "') do (
if NOT ERRORLEVEL 1 (
set flux_level=%%i
set /A flux_level=!flux_level:4,1!
)
)
But, if frob.exe is located at set frob=c:\path to frob\frob.exe then I get the error:
'c:\path' is not recognized as an internal or external command, operable program or batch file.
I've tried modifying the for loop with usebackq, but I get the same error:
for /f "usebackq tokens=4" %%i in ('"%frob%" -l ^| findstr "flux capacitor at "') do (
How do I get for /f to parse the output of a command with a complex path?
EDIT 1
This command:
for /F "tokens=4" %%i in ('"%frob%" -l ^| findstr /C:"flux capacitor at "') do (
expands to this:
for /F "tokens=4" %i in ('"c:\path to frob\frob.exe" -l | findstr /C:"flux capacitor at "') do (
'c:\path' is not recognized as an internal or external command,
operable program or batch file.
EDIT 2
I can verify the %frob% path is correct by putting:
"%frob%" --help
Just before the for /f loop. It works as expected and prints the application command-line help.
EDIT 3
If my findstr string is shorter and does not require quotes, then I don't get that error. For example, this command:
for /F "tokens=4" %%i in ('"%frob%" -l ^| findstr flux') do (
doesn't give me the error about frob's path.
for /f "tokens=4" %%i in ('"%frob%" -l ^| findstr /c:"flux capacitor at "') do (
set "flux_level=%%i"
set /A "flux_level=!flux_level:4,1!"
)
If %frob% contains spaces, quote it
a findstr command to search a string with spaces inside needs the search term indicated as /c:"..."
The commands executed in the in clause run in another cmd instance and the errorlevel is not accesible inside the do clause. If nothing is found, there will be no lines in the output of the pipe and the for will not execute the code in the do clause.
EDIT 1 - for command executes the command indicated in the in clause in a separate cmd instance. This instance retrieves, parses and executes the command. In some cases, the double quotes interfere, the initial and last quotes are removed (see cmd /? for more information) and the final command is wrong.
for /f "tokens=4" %%i in ('
" "%frob%" -l | findstr /c:"flux capacitor at " "
') do (
set "flux_level=%%i"
set /A "flux_level=!flux_level:4,1!"
)
Quote the full inner command in double quotes and remove the ^ in the pipe to handle the parse problem in the subshell
Remove the usebackq which changes the meanings of the different types of quotes.
The "quotes around the full program path and name" are required to escape the space-separators. the 'quotes round the command' are used to tell for /f that the string is a command to be executed. You'd probably get the same results using usebackq by using backticks (`) in place of single-quotes.
There's something mighty wrong here.
I've tried the following:
#ECHO OFF
SETLOCAL
SET "frob=u:\sourcedir\another dir\showparams.exe"
for /f "delims=" %%i in ('echo. ^|"%frob%" -l ') do (
ECHO %%i
)
ECHO ===============
SET "frob=u:\sourcedir\another dir\showparams.exe"
for /f "usebackq delims=" %%i in (`echo. ^|"%frob%" -l `) do (
ECHO %%i
)
ECHO ===============
FOR %%w IN ("%frob%") DO (
for /f "delims=" %%i in ('echo. ^|%%~dpnxsw -l ') do (
ECHO %%i
)
)
GOTO :EOF
Three different ways of executing a program located in a path containing spaces.
All worked perfectly - provided the file nominated as fob existed. Strangely, I received the same response as OP if the executable was missing :O
Obviously I don't have the OP's executable, but the method worked quite happily for me. I suspect an error in the value of frob.

Find the version of a installed program from batch file

We have a batch file that installs several programs as part of the developers setup. This is ran periodically when we get new versions of used components. So it would be nice only to install if the versions are different.
At the command prompt I can run this and get back the version installed:
wmic datafile where name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe' get version /format:list
Which gives the output Version=12.1.369.0.
However when I put this into a batch file like this and try to extract the version:
echo off
FOR /F "tokens=2 delims==" %%I in ('"wmic datafile where^(name^="C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe" get version /format:list"') DO (SET "RESULT=%%I")
ECHO %RESULT%
I get the response \\Common was unexpected at this time.
Some parts may be redundant as I've been trying stuff off the 'Net to correct this.
What have I missed?
You have a set of misplaced double quotes, as well as an extra (.
WMIC uses SQL syntax, and strings are enclosed in single quotes.The internal single quotes do not interfere with the command enclosing single quotes.
You can put double quotes around the WHERE clause (not including the WHERE keyword) to avoid some escape issues within the FOR DO() clause.
#echo off
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO SET "RESULT=%%I"
ECHO %RESULT%
But this may not quite be the whole solution. You can't see it with the above code, but RESULT actually contains a trailing carriage return (0x0D). This is due to a quirk with how FOR /F handles WMIC unicode output. Every line of WMIC output will have the extra trailing carriage return.
As long as you always access RESULT using %RESULT% (normal expansion), then you will not have any problems. But if you should ever need delayed expansion, then you can have problems, as demonstrated below.
#echo off
setlocal enableDelayedExpansion
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO SET "RESULT=%%I"
ECHO %RESULT%xxx
ECHO !RESULT!xxx
One convenient method to strip the unwanted carriage return is to use an extra level of FOR.
#echo off
setlocal enableDelayedExpansion
FOR /F "tokens=2 delims==" %%I IN (
'wmic datafile where "name='C:\\Program Files (x86)\\Common Files\\Company\\Product\\Version12\\Product.exe'" get version /format:list'
) DO FOR /F "delims=" %%A IN ("%%I") DO SET "RESULT=%%A"
ECHO %RESULT%xxx
ECHO !RESULT!xxx
Here's the subroutine I use for this in my own software update batch script:
:getfattr
set %1=
setlocal
set "name=%~f2"
set "name=%name:\=\\%"
for /f "delims=" %%A in ('wmic datafile where "name='%name:'=\'%'" get %1 /format:list') do #^
for /f "delims=" %%B in ("%%A") do endlocal & set "%%B" & goto :eof
echo>&2 getfattr failed
endlocal
goto :eof
It can get any file attribute supported by wmic datafile get. For example, here's how you might get the file version for the currently installed Adobe Reader:
call :getfattr version "%ProgramFiles(x86)%\Adobe\Reader 11.0\Reader\AcroRd32.exe"
echo "!version!"
After doing that, environment variable version will contain the requested version string. If :getfattr fails, version is guaranteed to be unset.
A test execution trace for that example looks like this (delayed expansion was already enabled, though this is not assumed by :getfattr):
>call :getfattr version "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
>set version=
>setlocal
>set "name=C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe"
>set "name=C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe"
>for /F "delims=" %A in ('wmic datafile where "name='C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe'" get version /format:list') do #for /F "delims=" %B in ("%A") do endlocal & set "%B" & goto :eof
>endlocal & set "Version=11.0.18.21" & goto :eof
>echo "!version!"
"11.0.18.21"
As you can see, it's pretty direct and doesn't faff about too much. It does, however, tiptoe through a minefield of cmd and wmic gotchas.
First, the name of the attribute you want to get is also the name used for the variable you want the result to end up in (version in the test above). Inside the subroutine, that name is %1, so set %1= clears it.
The filename you pass in needs a bit of preprocessing before it can be safely handed to wmic and a shell variable is required for that, so setlocal is issued to avoid stomping the caller's variables.
set "name=%~f2" copies the name to an environment variable after stripping off any surrounding double-quotes and expanding it to a full pathname. Double quotes surround the entire set argument to prevent grief caused by ampersands or parentheses in pathnames.
wmic queries use a SQL-like syntax, where string values are surrounded by single quote ' characters and \ is an escape that suppresses any special meaning of the following character. Since both of these are legal in Windows pathnames, all occurrences of either need a \ prefix. set "name=%name:\=\\%" escapes embedded backslashes, and the '%name:'=\'%' construct in the wmic command line escapes embedded single quotes and adds the required surrounding ones.
cmd's parser doesn't turn off special processing between single quotes, and the name no longer has any surrounding double quotes, so embedded spaces, parentheses or ampersands could potentially break things. To guard against that, wmic's entire name= argument gets double quoted. There's no need for special handling for double quotes already inside the name, because double quotes are prohibited in Windows filenames so there can't be any.
The for command line containing the wmic command ends with a #^ sequence. The ^ serves to attach the next line as the payload of the outer for command; the # prevents that payload being echoed in an execution trace even if ECHO is on.
That echo suppression is done mainly because the inner for exists only to get rid of the spurious CR characters injected by cmd's buggy conversion of wmic's output from Unicode to ASCII (the same technique used in #dbenham's answer) and if it's allowed to echo, those CRs just filthy up the trace with confusing overwrites. As a side benefit, the inner for won't execute its own payload when the line it's handed from the outer for contains only a CR, a version-dependent number of which wmic insists on emitting. The inner for's payload does get echoed if ECHO is on, so tracing still captures all the useful happenings.
That payload consists of three &-separated commands, which for will expand as a single command line before cmd gets to process the individual commands. In particular, this means that set "%%B" gets expanded before endlocal runs, which puts the variable created by that set outside the setlocal/endlocal scope and makes it available to the caller.
%%B will always expand in the format name=value because of the /format:list switch passed to wmic; the name will be the same as that specified with the get verb, and this is how the name you pass in ends up choosing the variable you get back. The entire name=value argument to set is quoted in case the requested attribute contains shell-special characters. This makes :getfattr itself safe, but you might want to use !delayed! expansion rather than %premature% expansion wherever you actually use the variable it hands back to you.
The & goto :eof on that same line breaks from both for loops and returns to :getfattr's caller as soon as the inner one actually does anything, just in case you pass in some weird name and wmic get produces more than one non-blank line of output.
The last three lines only ever run if wmic produces no output at all, which is what happens when it fails.
and two ways without external tools
1.WMIC
WMIC DATAFILE WHERE name="C:\\install.exe" get Version /format:Textvaluelist
Pay attention to the double slashes of file name.
Ready to use script/subroutine:
#echo off
:wmicVersion pathToBinary [variableToSaveTo]
setlocal
set "item=%~1"
set "item=%item:\=\\%"
for /f "usebackq delims=" %%a in (`"WMIC DATAFILE WHERE name='%item%' get Version /format:Textvaluelist"`) do (
for /f "delims=" %%# in ("%%a") do set "%%#"
)
if "%~2" neq "" (
endlocal & (
echo %version%
set %~2=%version%
)
) else (
echo %version%
)
exit /b %errorlevel%
Example (it needs a full file path):
call wmicVersion.bat "C:\Windows\System32\cmd.exe" cmdver
echo %cmdver%
2.MAKECAB
as the WMIC is not installed on home versions of windows here's a way with makecab that will run on every windows machine:
; #echo off
;;goto :end_help
;;setlocal DsiableDelayedExpansion
;;;
;;;
;;; fileinf /l list of full file paths separated with ;
;;; fileinf /f text file with a list of files to be processed ( one on each line )
;;; fileinf /? prints the help
;;;
;;:end_help
; REM Creating a Newline variable (the two blank lines are required!)
; set NLM=^
; set NL=^^^%NLM%%NLM%^%NLM%%NLM%
; if "%~1" equ "/?" type "%~f0" | find ";;;" | find /v "find" && exit /b 0
; if "%~2" equ "" type "%~f0" | find ";;;" | find /v "find" && exit /b 0
; setlocal enableDelayedExpansion
; if "%~1" equ "/l" (
; set "_files=%~2"
; echo !_files:;=%NL%!>"%TEMP%\file.paths"
; set _process_file="%TEMP%\file.paths"
; goto :get_info
; )
; if "%~1" equ "/f" if exist "%~2" (
; set _process_file="%~2"
; goto :get_info
; )
; echo incorect parameters & exit /b 1
; :get_info
; set "file_info="
; makecab /d InfFileName=%TEMP%\file.inf /d "DiskDirectory1=%TEMP%" /f "%~f0" /f %_process_file% /v0>nul
; for /f "usebackq skip=4 delims=" %%f in ("%TEMP%\file.inf") do (
; set "file_info=%%f"
; echo !file_info:,=%nl%!
; )
; endlocal
;endlocal
; del /q /f %TEMP%\file.inf 2>nul
; del /q /f %TEMP%\file.path 2>nul
; exit /b 0
.set DoNotCopyFiles=on
.set DestinationDir=;
.set RptFileName=nul
.set InfFooter=;
.set InfHeader=;
.Set ChecksumWidth=8
.Set InfDiskLineFormat=;
.Set Cabinet=off
.Set Compress=off
.Set GenerateInf=ON
.Set InfDiskHeader=;
.Set InfFileHeader=;
.set InfCabinetHeader=;
.Set InfFileLineFormat=",file:*file*,date:*date*,size:*size*,csum:*csum*,time:*time*,vern:*ver*,vers:*vers*,lang:*lang*"
example output (it has a string version which is a small addition to wmic method :) ):
c:> fileinfo.bat /l C:\install.exe
file:install.exe
date:11/07/07
size:562688
csum:380ef239
time:07:03:18a
vern:9.0.21022.8
vers:9.0.21022.8 built by: RTM
lang:1033
3 Using shell.application and hybrid batch\jscript.Here's tooptipInfo.bat :
#if (#X)==(#Y) #end /* JScript comment
#echo off
rem :: the first argument is the script name as it will be used for proper help message
cscript //E:JScript //nologo "%~f0" %*
exit /b %errorlevel%
#if (#X)==(#Y) #end JScript comment */
//////
FSOObj = new ActiveXObject("Scripting.FileSystemObject");
var ARGS = WScript.Arguments;
if (ARGS.Length < 1 ) {
WScript.Echo("No file passed");
WScript.Quit(1);
}
var filename=ARGS.Item(0);
var objShell=new ActiveXObject("Shell.Application");
/////
//fso
ExistsItem = function (path) {
return FSOObj.FolderExists(path)||FSOObj.FileExists(path);
}
getFullPath = function (path) {
return FSOObj.GetAbsolutePathName(path);
}
//
//paths
getParent = function(path){
var splitted=path.split("\\");
var result="";
for (var s=0;s<splitted.length-1;s++){
if (s==0) {
result=splitted[s];
} else {
result=result+"\\"+splitted[s];
}
}
return result;
}
getName = function(path){
var splitted=path.split("\\");
return splitted[splitted.length-1];
}
//
function main(){
if (!ExistsItem(filename)) {
WScript.Echo(filename + " does not exist");
WScript.Quit(2);
}
var fullFilename=getFullPath(filename);
var namespace=getParent(fullFilename);
var name=getName(fullFilename);
var objFolder=objShell.NameSpace(namespace);
var objItem=objFolder.ParseName(name);
//https://msdn.microsoft.com/en-us/library/windows/desktop/bb787870(v=vs.85).aspx
WScript.Echo(fullFilename + " : ");
WScript.Echo(objFolder.GetDetailsOf(objItem,-1));
}
main();
used against cmd.exe :
C:\Windows\System32\cmd.exe :
File description: Windows Command Processor
Company: Microsoft Corporation
File version: 6.3.9600.16384
Date created: ?22-?Aug-?13 ??13:03
Size: 347 KB
This is my filever bat file.
#echo off
If "%~1"=="" goto help
If "%~1"=="/?" goto help
If /i "%~1"=="/h" goto help
If "%~1"=="-?" goto help
If /i "%~1"=="-h" goto help
set filepath=%~f1
set file=%filepath:\=\\%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version"
echo %errorlevel%
goto finish
:help
Echo.
Echo. FileVer
Echo. -------
Echo.
Echo. Purpose:
Echo.
Echo. Reports the version number for an exe, dll, and similar files.
Echo.
Echo. Usage:
Echo.
Echo. filever ^<executable file^>
Echo.
Echo. filever [/h ^| -h ^| /? ^| -?] Starts this help
Echo.
echo. Examples:
Echo.
Echo. filever c:\windows\explorer.exe
Echo. filever "C:\Program Files\Windows NT\Accessories\wordpad.exe"
Echo. filever shell32.dll
Echo.
Echo. For Help
Echo.
Echo. filever
Echo. filever /?
Echo.
:finish
rem Pause if command double clicked
If /i "%cmdcmdline:~0,6%"=="cmd /c" pause
You seem to have an extra set of quotes around the whole command
One problem with for loops is it wmic outpus a blank line after the version.
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"') do set a=%%A & echo %%A
Put it in a file. Although the file has two blank lines.
set filepath=%~f1
set file=%filepath:\=\\%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version">test.txt
Maybe this could work
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"') do if not ""==%%A set a=%%A & echo %%A
Or call another batch file and don't return.
Here's a way to getrid of blank lines.
set filepath=%~f1
set file=%filepath:\=\\%
for /f "tokens=1 eol= " %%A in ('wmic datafile where name^="%file%" get version^|findstr /i /v /c:"version"^|findstr /i /v /r "^$"') do set a=%%A & echo %A%
wmic datafile where name^="%file%" get version|findstr /i /v /c:"version"|findstr /i /v /r "^$">test.txt
Here is an alternative method, bypasses WMIC for powershell Get-WmiObject.
#ECHO OFF
start /b powershell.exe -command "Get-WmiObject -Class CIM_DataFile -Filter \"Name='C:\\Program Files (x86)\\Knuckle.dll'\" | Select-Object Version"
PAUSE
Returns this result when double clicking a .cmd batch file.
Version
-------
0.0.0.0

batch file - counting number of files in folder and storing in a variable

I am very new to this. Please help me
I was trying to write a batch file program to count number of files in a folder and assign that to a variable and display it to verify that it has been stored
please help me with the syntax,
thank you in advance
-VK
I'm going to assume you do not want to count hidden or system files.
There are many ways to do this. All of the methods that I will show involve some form of the FOR command. There are many variations of the FOR command that look almost the same, but they behave very differently. It can be confusing for a beginner.
You can get help by typing HELP FOR or FOR /? from the command line. But that help is a bit cryptic if you are not used to reading it.
1) The DIR command lists the number of files in the directory. You can pipe the results of DIR to FIND to get the relevant line and then use FOR /F to parse the desired value from the line. The problem with this technique is the string you search for has to change depending on the language used by the operating system.
#echo off
for /f %%A in ('dir ^| find "File(s)"') do set cnt=%%A
echo File count = %cnt%
2) You can use DIR /B /A-D-H-S to list the non-hidden/non-system files without other info, pipe the result to FIND to count the number of files, and use FOR /F to read the result.
#echo off
for /f %%A in ('dir /a-d-s-h /b ^| find /v /c ""') do set cnt=%%A
echo File count = %cnt%
3) You can use a simple FOR to enumerate all the files and SET /A to increment a counter for each file found.
#echo off
set cnt=0
for %%A in (*) do set /a cnt+=1
echo File count = %cnt%
#echo off
setlocal enableextensions
set count=0
for %%x in (*.txt) do set /a count+=1
echo %count%
endlocal
pause
This is the best.... your variable is: %count%
NOTE: you can change (*.txt) to any other file extension to count other files.....
The mugume david answer fails on an empty folder; Count is 1 instead of a 0 when looking for a pattern rather than all files. For example *.xml
This works for me:
attrib.exe /s ./*.xml | find /v "File not found - " | find /c /v ""
This might be a bit faster:
dir /A:-D /B *.* 2>nul | find /c /v ""
`/A:-D` - filters out only non directory items (files)
`/B` - prints only file names (no need a full path request)
`*.*` - can filters out specific file names (currently - all)
`2>nul` - suppresses all error lines output to does not count them
To build for statement you should know some details at first.
for /F %%i in ('dir /A:-D /B *.* 2^>nul ^| find /c /v ""') do set "COUNT=%%i"
The example above would work, but if you want to copy paste it into another for-expression - might not.
The for /F ... expression by default has ; character as EOL character and space+tabulation characters as line separators.
If you use a file path as input in for-expression, then you can override these characters:
for /F "eol= delims=" %%i in (";My file path") do echo.Value: %%i
Where the end of eol= might not visible here. It is just a file path invalid not printable character, in this case - code 04. In most consoles and editors (except stackoverflow itself) you can type it as:
press ALT
type 04 from numeric keypad
release ALT
Another issue avoid here is always reset variable you want to use before the for-expression in case if for-expression is not executed:
set FILE=undefined
for /F %%i in (";My file path") do set "FILE=%%i"
echo.FILE=%FILE%
The fastest code for counting files with ANY attributes in folder %FOLDER% and its subfolders is the following. The code is for script in a command script (batch) file.
#for /f %%a in ('2^>nul dir "%FOLDER%" /a-d/b/-o/-p/s^|find /v /c ""') do set n=%%a
#echo Total files: %n%.
Change into the directory and;
attrib.exe /s ./*.* |find /c /v ""
EDIT
I presumed that would be simple to discover. use
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "batchfile.bat";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
I run this and the variable output was holding this
D:\VSS\USSD V3.0\WTU.USSD\USSDConsole\bin\Debug>attrib.exe /s ./*.* | find /c /v "" 13
where 13 is the file count. It should solve the issue
for /F "tokens=1" %a in ('dir ^| findstr "File(s)"') do echo %a
Result:
C:\MyDir> for /F "tokens=1" %a in ('dir ^| findstr "File(s)"') do #set FILE_COUNT=%a
C:\MyDir> echo %FILE_COUNT%
4 // <== There's your answer
FOR /f "delims=" %%i IN ('attrib.exe ./*.* ^| find /v "File not found - " ^| find /c /v ""') DO SET myVar=%%i
ECHO %myVar%
This is based on the (much) earlier post that points out that the count would be wrong for an empty directory if you use DIR rather than attrib.exe.
For anyone else who got stuck on the syntax for putting the command in a FOR loop, enclose the command in single quotes (assuming it doesn't contain them) and escape pipes with ^.
I have used a temporary file to do this in the past, like this below.
DIR /B *.DAT | FIND.EXE /C /V "" > COUNT.TXT
FOR /F "tokens=1" %%f IN (COUNT.TXT) DO (
IF NOT %%f==6 SET _MSG=File count is %%f, and 6 were expected. & DEL COUNT.TXT & ECHO #### ERROR - FILE COUNT WAS %%f AND 6 WERE EXPECTED. #### >> %_LOGFILE% & GOTO SENDMAIL
)
With a for loop:
FOR /F %i IN ('dir /b /a-d "%cd%" ^| find /v /c "?"') DO set /a count=%i
echo %count%
Without/avoiding for loop:
(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& cmd /c exit /b %myVar%)
set count=%errorlevel%
echo %count%
Tested in Win 10 cmd
Solution
Requires enabling Windows Subsystems For Linux
Ensure directoryToCount is set to the respective directory
SET directoryToCount=C:\Users\
dir %directoryToCount% > contentsOfDir.txt
echo cat contentsOfDir.txt ^| grep File > countFiles.sh
sh countFiles.sh
del countFiles.sh
del contentsOfDir.txt
Explanation
In both bash and batch environments, the output of a command can be redirected to a file using the > operator.
For example, echo hello world > myFile.txt will produce a file named myFile.txt with hello world as its text.
In a bash environment, one can cat the contents of a File and grep a particular line from the file containing a specified pattern.
For example, cat myFile.txt | grep hello will return lines containing hello
If Windows Subsystems for Linux is enabled, then one can execute sh from a Command Prompt to access a linux-like environment.
Therefore, we can solve this by doing the following
Use dir to acquire a list of files in the directory, as well as the number of files
Redirect the output of dir to a file (perhaps named contentsOfDir.txt).
Create a .sh file to grep for File from contentsOfDir.txt
Call the .sh file from command prompt to invoke the grep
Delete the .sh file
Delete contentsOfDir.txt

Resources