File name pattern matching in Windows command line - windows

I have several files like:
a.txt
a$.txt
a$b.txt
b.txt
b$.txt
b$c.txt
I would like to print file whose name does not contain '$' using Windows command line for file name pattern matching like regular expression:
for %%f in ([^$]+.txt) do type %%f
or
for %%f in ([a-zA-Z]+.txt) do type %%f
But it does not work. How can I do this using Windows command line? Thanks!

The for loop, like almost all cmd commands, does not support something like regular expressions. The only command that supports a tiny excerpt of those is findstr, which can be used together with dir to get the desired result:
#echo off
for /F "delims= eol=|" %%f in ('
dir /B /A:-D "*.txt" ^| findstr "^[^$][^$]*\.txt$"
') do (
>&2 echo/%%f
type "%%f"
)
This could even be simplified by replacing the portion findstr "^[^$][^$]*\.txt$" with find/V "$".

As 'Windows command line' includes powershell.exe as well as cmd.exe, I thought I'd offer a powershell based idea too.
Directly in powershell:
Get-Content -Path 'C:\Users\Xiagao\Desktop\*.txt' -Exclude '*$*.txt'
In cmd/batch-file, but leveraging powershell:
PowerShell -NoP "GC 'C:\Users\Xiagao\Desktop\*.txt' -Ex '*$*.txt'"
You would obviously modify the path to your source files location, (use .\*.txt for the current directory).

Related

How to list the names of all the files and directories in a folder using for loop in a batch file

I want to list all the files and directories inside a directory using a for loop in a batch script. How can I do it?
I used below but it didn't work :
for /r %%I in (".") do ( ls -ltr '%%I') ## Listing only filenames and not directories name
Any help is appreciable.
Thanks!
If you just want a list of dirs and files, recursively, what about:
dir /b/s "."
If you want to do something special with each of the stream item, using a for loop, you could do something like:
for /f "tokens=* delims=" %%i in ('dir /b/s "."') do ( echo "%%i" )
There I used echo for echoing, but you can put whatever you need.
"to list all the files and directories inside a directory using a for loop in a batch script." you should use the DIR command.
If you open a Command Prompt window, type dir /? and press the ENTER key you should see its usage information.
One important thing to note is the /A option. What is not mentioned specifically is that using it alone, (without additional parameters D, R, H, A, S, I, L or O), enables all attributes.
Therefore to list all items in the current directory recursively in bare format you'd use:
DIR /A /B /S
or
DIR . /A /B /S
If you wanted to list them in a specific location relative to the current directory, you'd use:
DIR "Location" /A /B /S
or:
DIR ".\Location" /A /B /S
And For a specific absolute path:
DIR "L:\ocation" /A /B /S
And if you wanted it to be in the same location as the batch file itself, you can use the special variable for the current script %0:
DIR "%~dp0." /A /B /S
To perform that command within a For loop, you should first open a Command Prompt window, type for /? and press the ENTER key, to read its usage information.
You should note that you are running a command, and should therefore use a FOR /F loop, i.e.
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
But should also note that:
To use the FOR command in a batch program, specify %%variable instead of %variable.
So:
FOR /F ["options"] %%variable IN ('command') DO command [command-parameters]
As you have your command already, the options now become important. The first you need to understand is eol which whilst it seems to mean End Of Line, is specific to only one end, the beginning! What this does it does not pass any result of 'command' to the DO if it begins with a single specific character. The defualt for eol is the semicolon ;, (probably because historically it was a common line comment marker in many files). Generally, a file or directory name could include, and begin with a semicolon, so in order to include all files, you would specify a character which cannot be included in a filename, for me the simplest is ?, although I've seen many examples using |. However, when you perform a recursive DIR command, every returned line is a fully qualified path, none of which can begin with a semicolon, so you can for this task ignore eol. You clearly want everything returned, so do not require skip any lines returned. tokens and delimiters, are adjusted according to what you want to do with the results, in this case, you want the entire content of each line returned by your 'command' with no splitting on specific characters. You should note that tokens by default is 1 and delims by default is both the space and a horizontal tab characters. You should stipulate therefore that you do not want any delimiters, so that the first token is everything returned on each line of 'command'. You rarely require the usebackq option, so for the purposes of this answer, and your task, just ignore it.
Now put it all together:
FOR /F "delims=" %%G IN ('DIR "Location" /A /B /S') DO command
Finally you can use your wanted DO command with each result from your parenthesized DIR command. That result will be held within your variable %%G.
For the purposes of just viewing each result, we'll use the ECHO command, (you would just replace that with your chosen command). Please note that as each result of the DIR command is a file or directory name string, you should generally doublequote it.
allObjects.cmd
FOR /F "delims=" %%G IN ('DIR "Location" /A /B /S') DO ECHO "%%G"
Please remember to replace "Location" as needed, before running the Windows Command Script
Create two loops, one for files
for /r %%i in (*.*) do <something>
and one for directories
for /r %%i in (.) do <something>
and use the same command after do
But, since you have Cygwin installed anyway, why not use that power and do
find . | xargs -L1 ls -ltr
where find . finds all files and directories, | xargs passes the output to xargs which -L1 splits the output after each line and passes each line to ls -ltr.

How to change extension from en.srt to .srt in command prompt

I have a list of en.srt files in my folder. I need to convert them to .srt extension.
For example
Criminal Minds - 1x01 - Extreme Aggressor.en.srt to Criminal Minds - 1x01 - Extreme Aggressor.srt
Tried the below command and it didn't work,
ren *.en.srt *.srt
Renaming extension like ren *.srt *.srv works. (Changing all files' extensions in a folder with one command on Windows)
Would like to know if there is a workaround for this?
A simply though clumsy method is to rename the files twice – first remove .srt, then change .en to .srt (given that there are no other files *.en):
ren "*.en.srt" "*." & ren "*.en" "*.srt"
A more elegant solution is the one provided by user Mofi in his comment:
#for /F "eol=| delims=" %I in ('dir "*.en.srt" /B /A:-D 2^> nul') do #for %J in ("%~nI") do #ren "%~I" "%~nJ%~xI"
In a batch-file this code would look similar to this (note the necessarily doubled %-signs):
#echo off
rem // Loop through all matching files:
for /F "eol=| delims=" %%I in ('dir "*.en.srt" /B /A:-D 2^> nul') do (
rem /* There are `~`-modifiers for `for` meta-variables that allow to split file names:
rem `~n` returns the base name, so the (last) extension becomes removed;
rem `~x` returns the extension (including the leading `.`);
rem therefore, `%%~nI` is the original file name with `.srt` removed, hence
rem ending with `.en`, and `%%~xI` is the original extension `.srt`;
rem another loop is used to also split off `.en` from `%%~nI`: */
for %%J in ("%%~nI") do (
rem /* Now `%%~J` returned the same as `%%~nI`, but `%%~nJ` removes `.en`;
rem so finally, rename the file to `%%~nJ` plus the original extension `.srt`: */
ren "%%~I" "%%~nJ%%~xI"
)
)
Following the thorough thread How does the Windows RENAME command interpret wildcards? on Super User, I found out that there is a way using a single ren command:
ren "*.en.srt" "?????????????????????????????????????????.srt"
However, you need to make sure to have enough ?, namely as many as there are characters in longest matching file name without .en.srt; otherwise, file names become truncated. You can avoid truncation by replacing the same sequence of ? instead of *, so longer file names are not renamed at all:
ren "?????????????????????????????????????????.en.srt" "?????????????????????????????????????????.srt"
Anyway, this only works when the original file names do not contain any more . besides the two in .en.srt; otherwise, everything behind the first . becomes removed and (finally replaced by srt).
Not difficult in PowerShell to identify the files and replace the end of the filename with a regex. When you are confident that the files will be renamed correctly, remove the -WhatIf from the Move-Item command.
powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem -File -Path '.' -Filter '*.en.srt' |" ^
"ForEach-Object {" ^
"Move-Item -Path $_.FullName -Destination $($_.FullName -replace 'en.srt$','srt') -WhatIf" ^
"}"
Of course, it would be easier if the command shell were PowerShell. BTW, this exact same code would work on Linux and Mac without change.
Get-ChildItem -File -Path '.' -Filter '*.en.srt' |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $($_.FullName -replace 'en.srt$','srt') -WhatIf
}
I don't have a cmd at my disposition but I would guess that
ren *.en.srt *.tmp
ren *.tmp *.srt
works

How to show only filenames without extensions using dir command

I'm trying to list out file names excluding their extension,
How I want it:
File1
File2
File3
How it currently is:
File1.txt
File2.txt
File3.txt
I tried using
#echo off
dir /A:-D /B
pause
but it isn't working. I tried it in both a batch file and in command prompt.
Am I using the right command?
Use FOR and ECHO to achieve this
For example, assuming the extension is always .txt:
for %f in ("*.txt") do #echo %~nf
Instead of using DIR, we are using the FOR command to go through the list and sending each one to ECHO, with the "~n" option inserted into the %f, to cause the extension to be not shown.
An alternative is
FORFILES /c "cmd /c echo #fname"
However with this I get quotation marks around each output filename, which isn't what you want.
If running inside a batch file, you need to double the %'s for variables
for %%f in ("*.txt") do #echo %%~nf
If you need to handle multiple file extensions
As long the directory doesn't contain any subdirectories whose names have an extension, you can generalise the *.txt to *.*:
for %f in ("*.*") do #echo %~nf
If you may have some filenames with only an extension
Where the file has an extension but nothing before it, e.g. .gitignore, the resulting empty ECHO command will output an inane message, such as ECHO is on. To avoid this ruining your onward plans, you can filter out lines containing ECHO is, with the FIND command and the /V option:
for %f in ("*.*") do #echo %~nf | find /v "ECHO is"
If your local language causes DOS to output something other than ECHO is then this filtering will not work. And it will miss any file that happens to contain ECHO is in the filename.
To search subdirectories too, add '/R' to the 'for'
for /R %f in ("*.png") do #echo %~nf | find /v "ECHO is"
Conclusion
This is all crazy, of course, but this is the agonising price we pay for using Batch language instead of an actual sensible language. I am like an alcoholic, promising to all and sundry that I will never write a line of Batch code again, and then finding myself coming back to do so again, sheepishly.
It'll be much easier in PowerShell
(Get-ChildItem -File).BaseName
or
Get-ChildItem | ForEach-Object { $_.BaseName }
Get-ChildItem can be replaced with the aliases ls, gci or dir and ForEach-Object can be replaced with %
So from cmd you can run either of these to achieve the purpose
powershell -Com "(ls -File).BaseName"
powershell -C (ls^ -File).BaseName
powershell (ls^ -af).BaseName
To add to Eureka's answer, the vanilla dir command cannot achieve what you're looking for.
C:\Users\jacob>dir /?
Displays a list of files and subdirectories in a directory.
DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]
[drive:][path][filename]
Specifies drive, directory, and/or files to list.
/A Displays files with specified attributes.
attributes D Directories R Read-only files
H Hidden files A Files ready for archiving
S System files I Not content indexed files
L Reparse Points - Prefix meaning not
/B Uses bare format (no heading information or summary).
/C Display the thousand separator in file sizes. This is the
default. Use /-C to disable display of separator.
/D Same as wide but files are list sorted by column.
/L Uses lowercase.
/N New long list format where filenames are on the far right.
/O List by files in sorted order.
sortorder N By name (alphabetic) S By size (smallest first)
E By extension (alphabetic) D By date/time (oldest first)
G Group directories first - Prefix to reverse order
/P Pauses after each screenful of information.
/Q Display the owner of the file.
/R Display alternate data streams of the file.
/S Displays files in specified directory and all subdirectories.
/T Controls which time field displayed or used for sorting
timefield C Creation
A Last Access
W Last Written
/W Uses wide list format.
/X This displays the short names generated for non-8dot3 file
names. The format is that of /N with the short name inserted
before the long name. If no short name is present, blanks are
displayed in its place.
/4 Displays four-digit years
Switches may be preset in the DIRCMD environment variable. Override
preset switches by prefixing any switch with - (hyphen)--for example, /-W.
Additionally, as an alternative to the suggestion to use ("*.txt"), if your file list includes multiple extensions you might either exclude different extensions or use *.* to get all files with a . in the name. Play around with that glob to get what you want out of it.
This is possible with a dir command and a for loop:
#echo off
for /F "delims= eol=" %%A IN ('dir /A-D /B') do echo %%~nA
If you want the full path without the extension, try:
#echo off
for /F "delims= eol=" %%A IN ('dir /A-D /B') do echo %%~dpnA
For cmd one-line:
for /F "delims= eol=" %A IN ('dir /A-D /B') do echo %~nA
And for the full path without the extension, try:
for /F "delims= eol=" %A IN ('dir /A-D /B') do echo %~dpnA
These small programs, loop through all the files in the folder except directories, and echo only the filenames/full paths without the extension.
dir -Name -File
This is for PowerShell

List subdirectory contents with date created/modified in CMD

In short: In Windows CMD, I need to list all the contents in all of the sub-directories of a folder, and their date-created or date-modified timestamps.
In long:
I want to regularly run a command which outputs the creation datetimes of files we upload to our FTP. I'm able to do this for one folder at a time and get the output in a text file (dir . h:\uploadtimes.txt). I'd like to do this for over 100 folders in one go. Filename and datetime-created is all I need.
THANKS!
dir /? could help (or read command reference); one could use /TC switch instead of /TW one:
dir X:\folder\*.* /S /A-D /-C /TW > h:\uploadtimes.txt
Another approach giving fully qualified file names but always date-modified timestamp regardless of /T switch unfortunately:
for /F "delims=" %G in ('dir X:\folder\*.* /S /B /A-D') do #echo %G %~TG > h:\uploadtimes.txt
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~G etc. special page) Command Line arguments (Parameters)

How do I find a directory in and store it into a variable, using a Windows batch file?

I need to find the location of a specific directory, and then store that directory path into a variable within a Windows batch script.
I also want the command to return when it finds a match (to avoid searching the entire hard drive once the directory has already been found).
So far I've tried this on the command line:
dir c:\ /s /b /ad | find "DirectoryName"
The problem with this is that it searches the entire drive, even after a match is found. Plus, I still can't figure out how to store the result in a variable within a batch file. There should only be a single result.
Basically I need the equivilent of somehting like this on Linux/bash:
export DIRPATH=`find / -name "DirectoryName" -print -quit`
Thanks for looking!
In batch you need FOR /F to get the output of a command.
FOR /F "usebackq delims=" %%p IN (`dir c:\ /s /b /ad ^| find "DirectoryName"`) DO (
set "DIRPATH=%%p"
)
echo %DIRPATH%
As there are quotes in the find command you need the usebackq-option.
And it's necessary to escape the pipe character one time, as it should pipe the dir command, not the for command

Resources