I want to get the latest 5 files in a directory.
This gave me the latest file:
FOR /F "delims=|" %%I IN ('DIR "*.yaml" /B /O:D') DO SET NewestFile=%%I
Any help is greatly appreciated
The following example is intended to perform the task as laid out in your question and as implied by my advisory comment:
#Echo Off
SetLocal DisableDelayedExpansion
For /F "Delims==" %%A In ('"Set Newest[ 2>NUL"')Do Set "%%A="
For /F "Tokens=1* Delims=:" %%A In (
'"Dir /B/A:-D/O:-D/T:W "*.yaml" 2>NUL|FindStr /LINE ".yaml""'
)Do If %%A LEq 5 (Set "Newest[%%A]=%%B")Else GoTo :Next
:Next
Set Newest[ 2>NUL&&Pause
I have used the most recently written in the above example and the last line was included just to show you any variables set within the For loop.
Here is another way to get the five (5) newest files according to "last write time." Be sure to change the -Path directory to yours.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "delims=" %%f IN ('powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem -Path "C:\src\t" -Filter '*.yaml' |" ^
"Sort-Object -Property LastWriteTime -Descending |" ^
"Select-Object -First 5 |" ^
"ForEach-Object { $_.FullName }"') DO (
SET "NEWFILE=%%~f"
ECHO Do something with "!NEWFILE!"
)
Related
As specified in the Question title, I have the following DIR command to get most recently modified files in any directory provided the command or script with this command in running in the same directory whose files list is to be filtered.
dir /b /o:-d
But the quirk here is that I want to limit the number of files in the most-recently-modified files list such that I can run for loop on each. This list needs to be generated without using multiple FOR loops, which I can't think of any way to figure out. I can loop thro' the whole list like below:
for /F "delims=" %%a in ('dir /b /o:-d') do echo %%a
How do I reliably stop this loop strictly when most recent n files are already listed ??
I suggested you could use a prior example and modify it to accept 6 such as below where you can add a number via command line, you attempted to make a change but would be better off using this version with !count! rather than trying %%
Latest.cmd
usage: latest 6
#ECHO OFF
setlocal EnableDelayedExpansion
set "j=0"
set "count=%1"
FOR /f "delims=" %%i IN ('dir /b /a-d /o-d *.*') DO (
echo %%i
set /A j=j+1
if !j! geq !count! (
goto :end
)
)
:end
For a single line showing first 6 but continuing without break that translates to
cmd /V:ON /c "set "latest=6" & set "j=0" & echo/ & for /f "tokens=*" %F in ('dir /b /a-d /o-d *.*') do #set /A "j=!j!+1" >nul & if !j! leq !latest! echo %F"
A much simpler version for break after say 6 files would be a modification to dbenham's answer
#echo off
set n=0
set count=6
for /f "usebackq delims==" %%F in (`dir /b /a-d /o-d *.*`) do (
echo %%F
set /a "n+=1, 1/(%count%-n)" 2>nul || goto :break
)
:break
set n=
set count=
For a cmd one line command it needs to be a bit more convoluted Change the 6 towards the end, to your desired number. (I am sure others will do better! since I am nesting cmd from the cmd line)
cmd/r "#echo off&echo/&for /f "usebackq tokens=*" %F in (`dir /b /a-d /o-d *.*`)=do=(echo=%F&set /a "n+=1,1/(6-n)" 1>nul=2>nul||(exit /b))"
Another way to do it in a cmd batch-file.
SET "FILECOUNT=6"
powershell -NoLogo -NoProfile -Command ^
(Get-ChildItem -File ^| Sort-Object -Property LastWriteTime ^| Select-Object -Last %FILECOUNT%).Name
The scope is running from the user's local computer.
You can use this to get the active user's SID.
Then you could use this with the HKU registry hive.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO GET THE NAME OF THE ACTIVELY LOGGED ON USER
FOR /F "skip=1" %%G IN ('wmic computersystem get username') DO (
SET aUSER=%%G
GOTO EXITLOOP1
)
:EXITLOOP1
ECHO %aUSER%
ECHO[
REM ECHO TRIM THE USERNAME
SET tUSER=%aUSER:~4%
REM ECHO %tUSER%
ECHO[
ECHO GET SID FOR USER: %tUSER%
FOR /F "usebackq skip=1" %%a IN (`WMIC USERACCOUNT WHERE NAME^='%%tUSER%%' GET SID`) DO (
SET SID=%%a
GOTO EXITLOOP2
)
:EXITLOOP2
ECHO %SID%
BTW, if you wanted to do it without a For loop, you could ask powershell to assist:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "(%SystemRoot%\System32\whoami.exe /User /Fo CSV | ConvertFrom-Csv).SID"
Or even without whoami.exe:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "Add-Type -AssemblyName System.DirectoryServices.AccountManagement;$([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).SID.Value"
In a cmd.exe console the following command can be used.
powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).Sid.AccountDomainSid.Value"
To get the result into a variable, use a FOR loop. (Yeah, I know, it's crazy, right?)
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).Sid.AccountDomainSid.Value"') DO (
SET "USER_SID=%%~A"
)
ECHO USER_SID is set to %USER_SID%
There are many other things that can be accessed in this way.
powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"[System.DirectoryServices.AccountManagement.UserPrincipal]::Current |" ^
"Format-List * -Force"
As you've raised a question, and in it decided to post some code, I'll offer a quicker and more simple alternative, regardless of whether you decide to post yours as a solution:
From cmd:
For /F Tokens^=3^ Delims^=^" %G In ('%SystemRoot%\System32\whoami.exe /User /Fo CSV /NH') Do #Echo %G
From a batch-file:
#For /F Tokens^=3^ Delims^=^" %%G In ('%SystemRoot%\System32\whoami.exe /User /Fo CSV /NH') Do #Echo %%G
I have a snippet of code this site helped me with and I would like to alter to behave in a different way if possible?
Running the file on a local PC directly will scan the user profile folders, omits system profiles (to avoid unnecessary scanning) and deletes 2 specified folders from every users app data local folder.
What I need to do now is run it across the network where I have a list of hostnames and do it that way. The below is working running directly on the PC.
For /F "Skip=1 Delims=" %%A In (
'"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
) Do For /F "Delims= " %%B In ("%%A") Do (
For %%I In (Folder1 Folder_2) Do (If Exist "%%B\AppData\Local\%%I\" (
RMDIR "%%B\AppData\Local\%%I" /S /Q >nul 2>&1)
)
)
I would like to change it to something like
for /f "usebackq tokens=*" %%A in ("%~dp0hostnames.txt") do (
For /F "Skip=1 Delims=" %%A In (
'"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
) Do For /F "Delims= " %%B In ("%%A") Do (
For %%I In (Folder1 Folder_2) Do (If Exist "\\%%B\C$\AppData\Local\%%I\" (
RMDIR "\\%%B\C$\AppData\Local\%%I" /S /Q >nul 2>&1)
)
)
I have had a go but it's getting beyond my limited knowledge, I think I need delayedexpansion and also move on the variable letter further along the alphabet but I dont know in which direction :-
Any help appreciated ..thanks
This is completely untested, but I'm assuming that you can utilise the /Node option of WMIC:
#Echo Off
For /F "UseBackQ Delims=" %%Z In ("%~dp0hostnames.txt"
) Do For /F "UseBackQ Skip=1 Delims=" %%X In (`WMIC /Node:'%%~Z' Path^
Win32_UserProfile Where "Special='False'" Get LocalPath`
) Do For /F "Delims=" %%Y In ("%%X") Do Call :Sub "%%~Z" %%Y
Exit/B
:Sub
For /F "Tokens=1* Delims=:\" %%V In ("%~2") Do For %%U In (Folder1 Folder_2
) Do If Exist "\\%~1\%%~V$\%%~W\AppData\Local\%%~U"^
RD/S/Q "\\%~1\%%~V$\%%~W\AppData\Local\%%~U"
GoTo :EOF
Here is a way to do it in PowerShell. When you are confident that the correct directories will be removed, remove the -WhatIf switch from the Remove-Item command.
$dirlist = 'dir1', 'dir2'
$userdirs = (Get-CimInstance -ClassName Win32_UserProfile -Filter "Special=$false").LocalPath
foreach ($ud in $userdirs) {
foreach ($d in $dirlist) {
if (Test-Path -Path "$ud\$d") {
Remove-Item -Path "$ud\$d" -Recurse -WhatIf
}
}
}
Using Invoke-Command will allow you to run the script on all computers simultaneously. This assumes that the previous script was saved as udscan.ps1.
Invoke-Command -ComputerName 'host1', 'host2' -FilePath .\udscan.ps1
i have a folder and it contains hundreds of text file, i want to rename it .
file names ABCD01%%.txt or CAT9999&#.txt OR FILENAME2345&^$.txt
i want to rename file such that anything that comes between 'numbers' and '.txt' should be removed
for example
ABCD01%%.txt becomes ABCD01.txt
CAT9999&#.txt becomes CAT9999.txt
FILENAME2345&^$.txt becomes FILENAME2345.txt
Code so far:
#echo off
for /f "tokens=*" %%f in ('dir /l /a-d /b *.txt') do (
for /f "tokens=1 delims=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" %%n in ("%%~nf") do (
echo File: %%~nxf = value %%n
rename %%~nxf *%%n.txt
)
)
Another solution i get for linux is rename 's/[^a-zA-Z0-9_]//g' *.txt , i tried to port it for windows but i cant .. how can the above command be ported to windows (batch)
Assuming there are no duplicate renames and assuming that only letters and numbers make up the first part of the filename, the following code will rename the files. When you are satisfied that the renaming is being done correctly, remove the -WhatIf from the Rename-Item command.
Get-ChildItem -File -Filter '*.txt' |
Where-Object { $_.Name -match '([A-Za-z0-9]*).*\.txt' } |
ForEach-Object { Rename-Item $_.FullName "$($matches[1]).txt" -WhatIf }
If you are not running in PowerShell, put the code into a renfunc.ps1 file and invoke it from the cmd .bat script.
powershell -NoProfile -File 'renfunc.ps1'
I've encountered a few problems with escaping characters, I had to use a slightly different method. This script should work:
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
set name=%%~nf
for /f "delims=0123456789 tokens=2" %%r in ("%%~nf") do set replace=%%r
set "replace=name:!replace:^^=!="
for /f %%x in ("!replace!") do set replace=!%%x!
ren "!name!.txt" "!replace!.txt"
)
EDIT: This revised script looks for the last numbers in the file name. [Don't mind the errors, they don't have any effect on the actual renaming.]
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
set name=%%~nf
set p=0
for /l %%# in (2 1 32) do (
for %%e in ("!name:~-%%#,1!") do (
echo.%%~e|findstr /r /i "[0-9]"&&if !p!==0 set /a p=%%#-1
)
)
set "new=name:~,-!p!"
for %%e in ("!name:~-1!") do echo.%%~e|findstr /r /i "^[0-9]"&&set new=name
for /f %%x in ("!new!") do ren "!name!.txt" "!%%~x!.txt"
)
EDIT: Revised again for the special case of "&&". Delayed expansion within a for-loop can be tedious. Now the characters won't break syntax anymore (which means the errors that were to be ignored have ceased).
I'm a newbie at this but have spent the afternoon searching your forums. While there are several posts about the ren command i can't seem to get mine to work?!
I would like to change:
A22-7000
A22-7001
A22-7003
to:
A24-7000
A24-7001
A22-7003
I opened the cmd window in the folder location and tried various forms of the following:
ren *A22 *A24
I know this should be easy but it's been driving me insane! Also, if anyone has a link to good tutorials where I can learn this sort of this that would be great!
Thanks!
you got the concept of wildcards wrong.
*A22 means "anything that ends with A22"
* means "any count of characters"
? means "one character"
What you want is probably:
ren A22* A24*
A22* means "anything that starts with A22 followed by any number of chars"
first you should certain you want change folder or file name when you use just ren that rename all find with your wild card !
see my example
if you have A22-7000 file and folder when you ren A22* A24* you change all folder and file if you want change
just folder
random.bat
dir /A:D /b | findstr.exe /n /R "a*" > s:\sites\file-count.txt
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt"') do set NUMBER-OF-FILES=%%A
FOR /L %%A IN (1,1,%number-of-files%) DO CALL rename.bat %%A
rename.bat
:rename
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt" ^|
findstr "%1:"') do ren %%B a24-%RANDOM%
just file :
random.bat
dir /A:-D /b | findstr.exe /n /R "a*" > s:\sites\file-count.txt
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt"') do set NUMBER-OF-FILES=%%A
FOR /L %%A IN (1,1,%number-of-files%) DO CALL rename.bat %%A
rename.bat:
FOR /F "tokens=1-10 delims=:" %%A IN ('type "s:\sites\file-count.txt" ^|
findstr "%1:"') do ren %%B a24-%RANDOM%
also you can do this with powershell script like
just for folder
gci -Directory -Filter A22* | foreach { Rename-Item $_.Name -NewName A24* }
just for file
gci -file -Filter A22* | foreach { Rename-Item $_.Name -NewName A24* }