I want to sort following files with DIR by their Timestamp, which is defined in the filename - oldest first:
Timestamp = YYYYDDMM
NAME_20121410.dat
NAME_20121509.dat
NAME_20121609.dat
The result should look like this:
NAME_20121509.dat
NAME_20121609.dat
NAME_20121410.dat
How do i achieve that with an one-liner?
As the date format is stupid, you need to split first the filenames and sort the rearranged names.
Not a one liner, but it works (inside a batch file).
#echo off
(
for %%A in (*_*.dat) do #(
call set "name=%%A"
call set "nameDate=%%name:*_=%%"
call set "Year=%%nameDate:~0,4%%"
call set "Day=%%nameDate:~4,2%%"
call set "Month=%%nameDate:~6,2%%"
call echo %%Year%%%%Month%%%%Day%% %%name%%
)
) | sort | (
for /F "tokens=1,* delims= " %%A in ('more') DO #echo %%B
)
if you can use PowerShell, try this:
PS II> ls *.dat | sort {$_ -replace '(\d{2})(\d{2})\.*','$2$1'}
Related
I am having trouble with this script. I'll explain below the codeblock.
#Echo off
pushd "\\server\folder"
SETLOCAL EnableDelayedExpansion
#FOR /F "TOKENS=2" %%A IN ('WHERE /T "testfiles*.*"') DO #(
set fdate123=%%A
echo !fdate123:~5,9!0!fdate123:~0,1!!fdate123:~2,2!
call StringLen !fdate123!
)
pause
:StringLen
Setlocal EnableDelayedExpansion
:: strLen String [RtnVar]
:: -- String The string to be measured, surround in quotes if it contains spaces.
:: -- RtnVar An optional variable to be used to return the string length.
Set "s=#%~1"
Set "len=0"
For %%N in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%N,1!" neq "" (
set /a "len+=%%N"
set "s=!s:~%%N!"
)
)
Endlocal&if "%~2" neq "" (set %~2=%len%) else echo %len%
Exit /b
What I'm trying to do it get the date modified of the file, and change the format of that date returned to YYYYMMDD. I want the date modified to be appended to the filename. I can have files from multiple days in this folder and each file may have a different date modified date.
Please do not mark this as a duplicate question, because I could not find this approach to doing this here.
I was trying to test for date string length so I can handle dates like 1/1/2019 (length of 8) vs 1/13/2019 (length of 9) vs 10/1/2019 (length of 9) vs 10/22/2019 (length of 10) then using if statements parse the date appropriately with the likes of something like !fdate123:~5,9!!fdate123:~0,1!!fdate123:~2,2! - I have not finished this yet.
I have tried getting the date with dir /T:W testfiles*.* and running a findstr but I don't understand findstr well enough to do that.
I also tried to pull it from forfiles /M BC_Services_Adjustment* /C "cmd /c echo #fdate" and moved on from that as well.
maybe somebody has a better solution, I think mine is a mess right now. Does anybody know how to get the date modified time stamp of every file in a folder, convert it a variable with YYYYMMDD format and then append it into all the files in a folder?
Note: I am not looking for powershell solutions for this question, please do not waste your time posting powershell answers.
Update #2 (5/21/19)
I tried magoo's code, I'm still needing a solution to rename the files.
#echo off
pushd "\\server\folder"
SETLOCAL EnableDelayedExpansion
FOR /F "TOKENS=2" %%A IN ('WHERE /T "*.csv"') DO (
for /f "tokens=1-3delims=/-." %%i in ("%%A") do (
set "mm=00%%i"&set "dd=00%%j"&set "yy=0000%%k"
set "fdate123=!yy:~-4!!mm:~-2!!dd:~-2!"
)
rem echo to test if date modified matches to the right filenames.
echo !fdate123! ^& %%A
rem ren "%%~nxA" "%%~nxA!fdate123!"
)
pause
I have tried with the ren "%%~nxA" "%%~nxA!fdate123!" but it's not finding the file. Probably super simple. If somebody can make magoo's code do a rename instead of just echoing the date I can award out the bounty on this question.
Be sure to specify your extentions so if your bat file is in that directory, it will not also be renamed.
#echo off
pushd "\\server\path123"
SETLOCAL EnableDelayedExpansion
FOR /r %%f IN (*.csv, *.txt) DO SET filedatetime=%%~tf & ren "%%~nf.*" "%%~nf!filedatetime:~6,4!!filedatetime:~0,2!!filedatetime:~3,2!%%~xf
FOR /F "TOKENS=2" %%A IN ('WHERE /T "testfiles*.*"') DO (
for /f "tokens=1-3delims=/-." %%i in ("%%A") do set "mm=00%%i"&set "dd=00%%j"&set "yy=0000%%k"
set "fdate123=!mm:~-2!!dd:~-2!!yy:~-4!"
echo !fdate123!
)
should allow you to construct the data according to your wishes.
The inner if assigns mm, dd and yy as appropriate, using the delimiters specified analysing %%A as a literal. Each is prefixed by an appropriate number of zeroes. The required string is then constructed using substringing selecting the last 2/4 characters of the string, so an 8-character output is obtained.
I use dd/mm/yyyy format and haven't actually tested this method, but manipulating it to your requirements should be obvious, the only issue really being how to handle yy dates as distingct from yyyy dates, if that's a concern.
I figured this out on my own, pure batch solution.
Takes date modified, appends it to any filename in a directory in YYYYMMDD format. I really was overcomplicating it, can't believe I didn't come up with this prior to setting a bounty. lol
pushd "\\server\folder"
SETLOCAL EnableDelayedExpansion
FOR /r %%f IN (*) DO SET filedatetime=%%~tf & ren "%%~nf.*" "%%~nf!filedatetime:~6,4!!filedatetime:~0,2!!filedatetime:~3,2!%%~xf"
Yes, I read that you do not want any PowerShell answers. Please be sure not to select this one as the answer. I did not waste my time writing something for you. This is for someone else who might get some benefit.
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[string]$CommandName
)
$dirlist = #('.') + ($Env:Path.Split(';'))
$extensions = #('') + ($Env:PATHEXT.Split(';'))
$results = foreach ($dir in $dirlist) {
if (($dir) -and ($dir -ne '')) {
if (Test-Path -Path $dir -ErrorAction SilentlyContinue) {
# The directory path exists.
# Check for presence of the file with any executable extension.
$dirhash = #{}
foreach ($extension in $extensions) {
Get-ChildItem -File -Path $dir -Filter "$CommandName$extension" |
ForEach-Object {
# If the file name is not already in the hash, add it to the hash
# and output it in the pipeline.
if (-not $dirhash.ContainsKey($_.Name)) {
$dirhash.Add($_.Name,1)
$_
}
}
}
}
}
}
$results | ForEach-Object {
Rename-Item -LiteralPath $_.FullName -NewName ($_.BaseName + $($_.LastWriteTime.ToString('yyyyMMdd')) + $_.Extension)
}
UPDATE:
Now that the OP's intent is known, this is a much more simple problem. Once you are confident the files will be renamed correctly, remove the -WhatIf from the Rename-Item cmdlet.
Set-Location -Path '//server/sharename'
Get-ChildItem -File -Filter 'testfiles*.*' |
ForEach-Object {
Rename-Item -LiteralPath $_.FullName -NewName ($_.BaseName + $($_.LastWriteTime.ToString('yyyyMMdd')) + $_.Extension) -WhatIf
}
I believe that the output from robocopy is in a consistent format, so I would suggest this as a possible single line batch-file option:
#PushD "\\server\folder" 2>Nul&&For /F "Tokens=1-4*Delims=/ " %%A In ('RoboCopy . $ testfiles*.* /L /NS /NJS /NJH /NDL /NC /TS')Do #Ren "%%E" "%%A%%B%%C-%%~nxE"
Alternatively, based upon your edited additional example code, this is more likely what you need:
#PushD "\\server\folder" 2>Nul&&For /F "Tokens=1-4*Delims=/ " %%A In ('RoboCopy . $ testfiles*.* /L /NS /NJS /NJH /NDL /NC /TS')Do #Ren "%%E" "testfiles%%A%%B%%C%%~xE"
If each renamed file is run through the for loop again, you may need to expand this from a single line solution to prevent it.
In both code examples, the Delimiters are /TAB
I have data in the below manner:
adb.hghgjjk.hkdhdl.Connhhhjj=hjkld\:hjkld\:thin\:hjdkdl\:3000\:abcdefg
I want to extract "abcdefg" from the above line using batch.
Above data can be changing so we need to read from the end of the line to backside and stop near : (colon) delimiter and extract it.
Any sugeestions?
Normally we do not give out code without the user at least making an attempt at trying to write some code and put some effort into researching the problem. Simple philosophy behind that is teaching a man to fish versus giving them the fish.
Give this a try.
#echo off
set "string=adb.hghgjjk.hkdhdl.Connhhhjj=hjkld:hjkld:thin:hjdkdl:3000:abcdefg"
set "first=%string::=" & set "last=%"
echo %last%
pause
If your data will never have a semicolon that you need to keep you could do this as well.
#echo off
set "string=adb.hghgjjk.hkdhdl.Connhhhjj=hjkld:hjkld:thin:hjdkdl:3000:abcdefg"
set "string=%string::=;%"
FOR %%G IN (%string%) do set "last=%%G"
echo %last%
pause
And one more example for good measure. The nice thing about batch files is alot of times there is more than one way to skin a cat.
#echo off
set "string=adb.hghgjjk.hkdhdl.Connhhhjj=hjkld:hjkld:thin:hjdkdl:3000:abcdefg"
:loop
FOR /F "tokens=1* delims=:" %%G IN ("%string%") do (
set "last=%%G"
IF NOT "%%~H"=="" (
SET "string=%%~H"
GOTO loop
)
)
echo %last%
pause
PowerShell can use regex expressions. The result is put into the R variable. If there is no match, R will be nothing.
#ECHO OFF
SET "S=adb.hghgjjk.hkdhdl.Connhhhjj=hjkld\:hjkld\:thin\:hjdkdl\:3000\:abcdefg"
SET "R="
FOR /F %%a IN ('powershell -NoLogo -NoProfile -Command ^
" '%S%' | Where-Object { $_ -match '.*:(.*$)' } | ForEach-Object { $Matches[1] } "') DO (SET "R=%%a")
ECHO R is %R%
I am looking for a batch script or PowerShell script that read values from a text file and place them in a script local variables.
For example the input file looks like:
input.txt
PARAM1=VALUE1
PARAM2=VALUE2
PARAM3=VALUE3
In the script I would like to place the values into three different variables like:
echo %variable1%
echo %variable2%
echo %variable3%
The output will be:
value1
value2
value3
I started the script like:
#echo off
setlocal
for /f "delims== tokens=1,2" %%G in ("input.txt") do set %%G=%%H echo %G%
Please provide me some insights or ideas
The code is almost okay except for:
usebackq option is needed if you specify the input file in doublequotes
echo %G% should be either echo !%%G! and of course you'll need setlocal enableDelayedExpansion at the start of the script or just before the loop.
Or in your case you can simply print the value in %%H.
use () for multi-line for-loops, otherwise separate the commands with & on the same line
use quotes in set as shown in the code below in case the values have special characters.
use echo. to print a line that could be empty (/,:,( may be used instead of dot)
for /f "delims== tokens=1,2 usebackq" %%G in ("input.txt") do (
set "%%G=%%H"
echo.%%H
)
I want to read values from a file and assign them to script local variables.
#echo off
setlocal
for /f "delims== tokens=1,2" %%G in ("input.txt") do set %%G=%%H echo %G%
Your batch file is close, but need a couple of tweaks:
In order to read the contents of input.txt in the for loop you need to type the file.
You have a mistake in your echo command, it should be %%G not %%H.
To display the variable names
test.cmd:
#echo off
setlocal
for /f "delims== tokens=1,2" %%G in ('type input.txt') do (set %%G=%%H && echo %%G)
endlocal
Example usage:
F:\test>type input.txt
PARAM1=VALUE1
PARAM2=VALUE2
PARAM3=VALUE3
F:\test>test
PARAM1
PARAM2
PARAM3
To display the values of the variables, replace echo %%G with echo %%H
test.cmd:
#echo off
setlocal
for /f "delims== tokens=1,2" %%G in ('type input.txt') do (set %%G=%%H && echo %%H)
endlocal
Example usage:
F:\test>type input.txt
PARAM1=VALUE1
PARAM2=VALUE2
PARAM3=VALUE3
F:\test>test
VALUE1
VALUE2
VALUE3
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
for /f - Loop command against the results of another command.
type - Display the contents of one or more text files.
If you want to use the PowerShell syntax can be:
$InputText = Get-Content "C:\Temp\input.txt"
$i=0 #add inkrement
ForEach ($line in $InputText)
{
$i++ #increment for variable numbers
($line -split "=")[1] | Set-Variable -Name ("variable$i")
}
#Show variables
$variable1
$variable2
#and so
More elegant than batch files :)
I have a large file full of lines like this...
19:54:05 10.10.8.5 [SERVER] Response sent: www.example.com. type A by 192.168.4.5
19:55:10 10.10.8.5 [SERVER] Response sent: ns1.example.com. type A by 192.168.4.5
19:55:23 10.10.8.5 [SERVER] Response sent: ns1.example.com. type A by 192.168.4.5
I don't care about any of the other data, only what's after the "response sent:"
I'd like a sorted list of the most common occurrences of the domain-names.
Problem is I won't know all the domain-names in advance, so I can't just do a search for the string.
Using the example above I'd like the output to be along the lines of
ns1.example.com (2)
www.example.com (1)
...where the number in ( ) is the counts of that occurrence.
How/what could I use to do this on Windows? The input file is .txt - the output file can be anything. Ideally a command-line process, but I'm really lost so I'd be happy with anything.
Cat is kinda out of the bag so lets try and help a little. This is a PowerShell solution. If you are having issues with how this works I encourage you to research the individual parts.
If you text file was "D:\temp\test.txt" then you could do something like this.
$results = Select-String -Path D:\temp\test.txt -Pattern "(?<=sent: ).+(?= type)" | Select -Expand Matches | Select -Expand Value
$results | Group-Object | Select-Object Name,Count | Sort-Object Count -Descending
Using your input you would get this for output
Name Count
---- -----
ns1.example.com. 2
www.example.com. 1
Since there is regex I have saved a link that explains how it works.
Please keep in mind that SO is, of course, a site that helps programmers and programming enthusiasts. We are devoting our free time where as some people get paid to do this.
Can you do it in PHP?
<?php
$lines = file($filename, FILE_IGNORE_NEW_LINES);
foreach($lines as $value) {
$arr = explode(' ', $value);
$domainarr[] = $arr[5];
}
$occurence = array_count_values($domainarr);
print_r($occurence);
?>
This is in batch:
#echo off
setlocal enabledelayedexpansion
if exist temp.txt del temp.txt
for /f "tokens=6" %%a in (input.txt) do (Echo %%a >> temp.txt)
for /f %%a in (temp.txt) do (
set /a count=0
set v=%%a
if "!%%a!" EQU "" (
for /f %%b in ('findstr /L "%%a" "temp.txt"') do set /a count+=1
set %%a=count
Echo !v:~0,-1! ^(!count!^)
)
)
del temp.txt
Currently it prints it out to the screen. If you would like to redirect it to a text file replace:
Echo !v:~0,-1! ^(!count!^)
with:
Echo !v:~0,-1! ^(!count!^) >> output.txt
This outputted:
www.example.com (1)
ns1.example.com (2)
With the sample data
This Batch file solution should run faster:
#echo off
setlocal
rem Accumulate each occurance in its corresponding array element
for /F "tokens=6" %%a in (input.txt) do set /A "count[%%a]+=1"
rem Show the result
for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a (%%b)
Output:
ns1.example.com. (2)
www.example.com. (1)
To store the result in a file, change the last line by this one:
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a (%%b^)) > output.txt
I have a script which can list all files under a folder and its subforlders, with some properties such as path, file name, modified date and size. But, I can't add one extra property, file owner.
#ECHO off
SET v1=%%~dpF
SET v2=%%~nxF
SET v3=%%~zF
(for /r %%F in (*) do #echo "%v1%","%v2%",%v3%) > test.csv
PAUSE
Basically I want to add a 4th parameter, which should show file owner. It is in Windows 7 environment.
You can use the dir command with the /q switch to include the owner of each file.
#ECHO OFF
SetLocal EnableDelayedExpansion
for /r %%a in (*) do for /f "tokens=5" %%b in ('dir /q "%%~fxa" ^| findstr "%%~nxa"') do (
echo "%%~dpa","%%~nxa","%%~za","%%b"
) >> test.csv
This will always append to test.csv, if you want to always recreate test.csv you can encase your entire for loop in parenthesis (as you had);
#ECHO OFF
SetLocal EnableDelayedExpansion
(for /r %%a in (*) do for /f "tokens=5" %%b in ('dir /q "%%~fxa" ^| findstr "%%~nxa"') do (
echo "%%~dpa","%%~nxa","%%~za","%%b"
)) > test.csv
Not exactly what you asked for, but I adapted a PowerScript to show what you ask for. Just update the PARAM section with your file and folder names, copy and paste into PowerShell and hit enter twice:
PARAM (
$Path = 'C:\Users\PATHHERE\',
$report = 'C:\Users\USERNAME\Desktop\OUTPUTFILENAMEHERE.csv'
)
$LastWrite = #{
Name = 'Last Write Time'
Expression = { $_.LastWriteTime.ToString('u') }
}
$Owner = #{
Name = 'File Owner'
Expression = { (Get-Acl $_.FullName).Owner }
}
$HostName = #{
Name = 'Host Name'
Expression = { $env:COMPUTERNAME }
}
Get-ChildItem -Recurse -Path $Path |
select $HostName, $Owner, Name, Directory, $LastWrite, Length |
Export-Csv -NoTypeInformation $Report
This script adapted from info found here. I find batch files to be more and more trouble to deal with these days, and PowerShell is very flexible. The guys over at serverfault.com will no doubt be able to help you better with these kinds of questions.