I'm try to find, in only one row, the number of files (*.rar) in a directory.
For doing this I'm using the commands:
for /f "delims=" %i in ('find /c ".rar" "D:\backup e ckpdb ept-icd\test\unload\lista_files_rar.txt"') do echo %i
but the value of %i I have at the end is : D:\BACKUP E CKPDB EPT-ICD\TEST\UNLOAD\LISTA_FILES_RAR.TXT: 8
I would like to obtain only the number 8 so instead to echo the value I would assign the value to a variable.
I use the command line : dir /b *.rar | find /c ".rar"
that it returns the value of rar files in the directory, but I can't assign the value to a variable, for example: dir /b *.rar | find /c ".rar" | set/a files =
I tried also to use the keyword tokens=2 but it doesn't work
p.s If it possible to do it only with the find command is also better
See here for example on counting files
Or you can simply do something like this (not tested)
for /F %%j in ('dir /B *.rar ^| find /C /V ""') do set count=%%j
This returns just the number; there might be a cleaner way to do it, but unfortuantly "find" can't take it's input from a pipe (i.e., I can't do dir | find):
#echo off
dir /b *.rar> out.tmp
for /f "usebackq tokens=3" %%i in (`find /c "rar" out.tmp`) do echo %%i
del out.tmp
Try "delims=: tokens=3"
You normally will have two colons in the result, one after the drive letter and one before the number you want, so your number should be token 3
Thank you, I think I will use
for /F %%j in ('dir /B *.rar ^| find /C /V ""') do set count=%%j
user135127
In this way I think also if somethink in the name of the dir the result should remain always the same.
which is the difference between :
dir /B *.rar ^| find /C /V "" and
dir /B *.rar ^| find /C ".rar" ?
for /f %a in ('dir "*.txt" ^| find "File(s)"') do set Count=%a
Gives
set Count=36
or you can use an arithmetic set and delayed environment variable expansion
set count=0
for %a in (*.txt) do #set /a Count=!Count!+ 1 > nul
echo %count%
gives
Count=36
Related
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0Files"`) DO #ECHO %%G
The output is the full path of the file/dir but I want to make it simpler by removing %~dp0's path from the output
This is the methodology I'd suggest you incorporate, which protects filenames which may include ! characters and limits the output to files, as per your stated requirement:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F Delims^=^ EOL^= %%G In ('Dir /B/S/A-D "%~dp0Files" 2^>NUL')Do (
Set "_=%%G" & SetLocal EnableDelayedExpansion
Echo(!_:*%~dp0Files=.! & EndLocal)
Pause
If you'd prefer not to have a relative path type output then change !_:*%~dp0Files=.! to !_:*%~dp0Files\=!
Alternatively, you could grab the relative paths using the slower, forfiles.exe utility:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE Echo #RelPath"
If you prefer it without doublequotes then this modification should do that:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For %%G In (#RelPath)Do Echo %%~G"
And if you wanted it without the leading .\ then perhaps:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For /F 0x22Tokens=1*Delims=\0x22 %%G In (#RelPath)Do Echo %%H"
You could also do this by leveraging powershell.exe:
%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoProfile Get-ChildItem -Path "%~dp0Files" -File -Force -Name -Recurse
which could possibly be done, (not recommended), in as short a line as:
powershell -NoP ls "%~dp0Files" -File -Fo -Na -Rec
just remove %~dp0 from each entry (Note: that doesn't work with %%G metavariables, you have to use a "normal" environment variable):
#echo off
setlocal enabledelayedexpansion
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0"`) DO (
set "file=%%G"
echo !file:%~dp0=!
)
To retrieve the relative path to a given root without string manipulation, you could use the xcopy command with its /L option, which lists relative paths to files it would copy without /L:
pushd "%~dp0" && (
for /F "delims= eol=|" %%G in ('xcopy /L /S /Y /I "Files" "%TEMP%" ^| find "\"') do (
echo(%%G
)
popd
)
pushd and popd are used to change into and return from the root directory, respectively.
The find command is used to suppress xcopy's summary line # File(s).
I have a folder which contains the following files:
How can I delete all files with extension .rst (File1.rst, File2.rst, File3.rst, File4.rst, File5.rst) except the file "index.rst" from a batch file.
I have tried this, but it's not working:
for /f "skip=1 delims=" %%i in ('D:\hfTools\Projects\Validation-Source\Docs\source /b "*.rst"') do #(if "%i" neq "index.rst" echo %i)
Any help would be welcome. Thank you.
Here's an example of how to perform the task using the ForFiles command, forfiles.exe:
#%__AppDir__%forfiles.exe /P "D:\hfTools\Projects\Validation-Source\Docs\source" /M "*.rst" /C "%__AppDir__%cmd.exe /D /C If #IsDir==FALSE If /I Not #FName==0x22index0x22 Del /A /F #File"
Here's an example of how to perform the task using the Dir command:
#Echo Off
SetLocal EnableExtensions
If Exist "D:\hfTools\Projects\Validation-Source\Docs\source\*.rst" (
PushD "D:\hfTools\Projects\Validation-Source\Docs\source" && (
For /F "EOL=? Delims=" %%G In ('Dir /B /A:-D "*.rst" ^
^| %__AppDir__%findstr.exe /E /I /L ".rst" ^
^| %__AppDir__%findstr.exe /I /L /V /X "index.rst"'
) Do Del /A /F "%%G"
PopD
)
)
My preference however would be to use the Where command, where.exe:
Example batch-file
#Echo Off
SetLocal EnableExtensions
For /F "EOL=? Delims=" %%G In ('%__AppDir__%where.exe ^
"D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst" ^
^| %__AppDir__%findstr.exe /E /I /L /V "\index.rst"'
) Do Del /A /F "%%G"
You could even do that as a single line batch-file:
#For /F "EOL=?Delims=" %%G In ('%__AppDir__%where.exe "D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst"^|%__AppDir__%findstr.exe /EILV "\index.rst"')Do #Del /A/F "%%G"
Or directly from a cmd window:
For /F "EOL=?Delims=" %G In ('%__AppDir__%where.exe "D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst"^|%__AppDir__%findstr.exe /EILV "\index.rst"')Do #Del /A/F "%G"
And for an off topic bonus, because for general use it seems easier; use powershell instead:
Remove-Item -Path "D:\hfTools\Projects\Validation-Source\Docs\source\*.rst" -Exclude "index.rst" -Force
You could even run that using a one line batch file, if you really needed to:
#%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP "RI 'D:\hfTools\Projects\Validation-Source\Docs\source\*.rst' -E 'index.rst' -Fo"
Not tested:
forfiles /M *.rst /C "cmd /c if #file!=index.rst del #file"
Explanation:
/M *.rst # only consider *.rst
if ... # #file is the filename as found by forfiles
# != is this the correct way say "does not equal"?
You are actually quite close, you just forgot to double a few %-signs and you missed the dir command:
rem // Change to target directory, because `dir /B` only returns pure file names:
pushd "D:\hfTools\Projects\Validation-Source\Docs\source" && (
rem // Capture the output of `dir /B` and loop through the lines/files:
for /f "delims= eol=|" %%i in ('
dir /B /A:-D-H-S "*.rst"
') do #(
rem // Check file name against predefined exception:
if /I not "%%i"=="index.rst" (
rem // Actually delete the currently iterated file:
ECHO del "%%i"
)
)
popd
)
Once you are satisfied with the output, remove the upper-case ECHO command to actually delete files.
Note that the pattern *.rst in the dir /B command line is actually checked against both long and short file names (if the latter is enabled), so it actually matches files whose extensions begin with rst (if applicable).
If the files to delete always match the pattern File*.rst you do not even need the if condition:
rem // Change to target directory, because `dir /B` only returns pure file names:
pushd "D:\hfTools\Projects\Validation-Source\Docs\source" && (
rem // Capture the output of `dir /B` and loop through the lines/files:
for /f "delims= eol=|" %%i in ('
dir /B /A:-D-H-S "File*.rst"
') do #(
rem // Actually delete the currently iterated file:
ECHO del "%%i"
)
popd
)
This is easily done using PowerShell. If you are on a supported version of Windows, PowerShell will be available. When you are confident that the correct files will be removed, remove the -WhatIf from the command.
Remove-Item -Path './*' -Include '*.rst' -Exclude 'index.rst' -WhatIf
Id you must do it from a cmd.exe (.bat file) script:
powershell -NoLogo -NoProfile -Command ^
"Remove-Item -Path './*' -Include '*.rst' -Exclude 'index.rst' -WhatIf"
I'm trying to list non-symbolic links in an specific directory and then delete them.
non-symbolic links definition: any file besides the ones that have been created using the command MKLINK /H
To identify those non-symbolic links I used the following approach:
#> fsutil hardlink list %file% | find /c /v ""
When the specified %file% is a symbolic link it returns a number bigger than 1, when it is just a simple file, it returns 1. So far so good!
My problem starts when I need to automate this process and get such return to compare if it is bigger than 1
That's is the code I'm trying to get running property:
#echo off
set some_dir=C:\TEMP\
for /f %%a in ('dir /b %some_dir%') do (
set count=fsutil hardlink list %%a | find /c /v ""
if %count% -EQU 1 del /Q %%a
)
Would someone explain me how such attribution and comparison on %count% variable could be done, please?
I'm trying to list non-symbolic links in an specific directory and then delete them.
There are some issues with your code.
for /f %%a in ('dir /b %some_dir%') do (
The dir /b doesn't work because it doesn't return a file name with a complete path (which is required as input for fsutil)
Use dir /b /s instead.
set count=fsutil hardlink list %%a | find /c /v ""
This doesn't set count to anything sensible.
Use another for /f and parse the output of fsutil so you can set a variable.
if %count% -EQU 1 del /Q %%a
This has two mistakes. You need to use delayed expansion to evaluate count correctly. Replace %count% with !count!. Also remove the -. Replace -EQU with EQU.
Try the following batch file.
test.cmd:
#echo off
setlocal enabledelayedexpansion
set some_dir=C:\TEMP\
for /f %%a in ('dir /b /s %some_dir%') do (
for /f %%b in ('fsutil hardlink list %%a ^| find /c /v ""') do (
set count=%%b
if !count! EQU 1 echo del /Q %%a
)
)
endlocal
Notes:
Remove the echo when you happy with what the result will be.
Example usage and output:
I have used f:\test\folder1 as my test directory. hard is a hardlink to 1.txt.
F:\test>dir f:\test\folder1
Volume in drive F is Expansion
Volume Serial Number is 3656-BB63
Directory of f:\test\folder1
29/08/2016 21:40 <DIR> .
29/08/2016 21:40 <DIR> ..
21/08/2016 09:46 0 1.txt
21/08/2016 09:46 0 2.txt
21/08/2016 09:46 0 3.txt
21/08/2016 09:46 0 4.txt
21/08/2016 09:46 0 5.txt
29/08/2016 21:38 <SYMLINK> file [f:\d]
21/08/2016 09:46 0 hard
29/08/2016 21:38 <SYMLINKD> test [f:\d]
7 File(s) 0 bytes
3 Dir(s) 1,764,846,960,640 bytes free
F:\test>test
del /Q f:\test\folder1\2.txt
del /Q f:\test\folder1\3.txt
del /Q f:\test\folder1\4.txt
del /Q f:\test\folder1\5.txt
del /Q f:\test\folder1\file
del /Q f:\test\folder1\test
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
dir - Display a list of files and subfolders.
enabledelayedexpansion - Delayed Expansion will cause variables to be expanded at execution time rather than at parse time.
for /f - Loop command against the results of another command.
There are some problems in your code:
you need delayed expansion because you are setting (writing) and expanding (reading) the variable count within the same parenthesised block of code (namely the for /F %%a loop);
in your for /F %%a loop you need to state options "eol=| delims=" in order not to run into trouble with files whose names begin with ; (such would be ignored due to the default eol=; option) and those which have white-spaces in their names (you would receive only the postion before the first white-space because of the default delims SPACE and TAB and the default option tokens=1 (see for /? for details about that);
dir /B returns file names only, so %%a actually points to files in the current directory rather than to C:\TEMP\; to fix that, simply change to that directory first by cd;
to capture the output of a command (line) and assign it to a variable, use another for /F loop and set; this loop is going to iterate once only, because find /C returns only a single line; note the escaped pipe ^| below, which is required to not execute it immediately;
there is no comparison operator -EQU, you need to remove the - to check for equality;
it is a good idea to use the quoted set syntax as it is most robust against poisonous characters;
file and directory paths should generally be quoted since they might contain token delimiters or other poisonous characters;
Here is the fixed script:
#echo off
setlocal EnableDelayedExpansion
pushd "C:\TEMP\" || exit /B 1
for /F "eol=| delims=" %%a in ('dir /B "."') do (
for /F %%b in ('
fsutil hardlink list "%%a" ^| find /C /V ""
') do (
set "count=%%b"
)
if !count! EQU 1 del "%%a"
)
popd
endlocal
This can even be simplified:
#echo off
pushd "C:\TEMP\" || exit /B 1
for /F "eol=| delims=" %%a in ('dir /B "."') do (
for /F %%b in ('
fsutil hardlink list "%%a" ^| find /C /V ""
') do (
if %%b EQU 1 del "%%a"
)
)
popd
Since the inner for /F loop iterates always once only, we can move the if query inside, thus avoiding the definition of an auxiliary variable which is the only one we needed delayed expansion for.
Simplified method:
#Echo Off
PushD X:\YourDirectory
For %%a In (*.*) Do (
FSUtil HardLink List %%a|FindStr/VIC:"%%~pnxa">Nul||(Echo=Del "%%~a"))
Pause
When you're satisfied with the output Remove line 5 and also 'Echo=' from line 4
I want to get the number of files modified before 10 days to a variable.
I can get number of files using
forfiles /P "D:\files" /S /D -10 | find /c /v ""
But when i try to assign it to a variable using FOR it gives error.
Command I used in FOR is
FOR /F "delims=" %i IN ('forfiles /P "D:\files" /S /D -10 | find /c /v ""') DO set today=%i
It actually works fine when I remove | find /c /v ""
FOR /F "delims=" %i IN ('forfiles /P "D:\files" /S /D -10 ^| find /c /v ""') DO set today=%i
in this case you need to escape the pipe.
Yes you can use the FIND command to count how many occurrences it finds but you don't need to. You could just use the set command to iterate a variable.
FOR /F "delims=" %%G IN ('forfiles /P "D:\files" /S /D -10') do #set /a count+=1
I want to write an batchfile that Deletes a folder
if the folder has more than 20 files in it. but I do not know how to do it.
I use Windows7 Ultimate.
List the files in bare format and use find command to count the number of output lines
set "nFiles=0"
for /f %%a in (
'dir /a-d /b "c:\folder\*" 2^>nul ^| find /c /v ""'
) do set "nFiles=%%a"
echo %nFiles%
List the files in usual format and use findstr to locate the line/field with the number of files
set "nFiles="
for /f %%a in (
'dir "c:\folder\*" ^| findstr /b /c:" "'
) do if not defined nFiles set "nFiles=%%a"
if not defined nFiles set "nFiles=0"
echo %nFiles%
Use a counter over the output of dir command
set "nFiles=0"
for /f %%a in ('dir /b /a-d "c:\folder\*" 2>nul ') do set /a "nFiles+=1"
echo %nFiles%
Or you can use wmic, or number the lines in the output of dir command with the usage of findstr /n, or ....
In any case
if %nFiles% gtr 20 rd /s /q "c:\folder"