I use Windows 7, and I a want to build a batch-file with to complete the following task:
Delete all files with 4 characters in name in the C:\images directory.
E.g. 1234.jpg 7123.jpg, 8923.jpg, 7812.jpg, 1245.jpg, 0067.jpg, 0001.jpg, 0010.jpg, 0060.jpg etc.
Is that possible?
This solution will erase all files whose name part before the dot have 4 characters, and possibly those that have a shorter part before the dot.
ERASE C:\images\????.*
? stands for any character (or sometimes no character at all, see below)
* stands for any sequence of characters.
What different Windows versions ?
Under Windows 98 (and I have a gut feeling that this is also valid for "pure" DOS versions without full support for long FAT names, which would include win95 and older, and maybe Windows Millennium), the ? stands for exactly one character.
Based on #dbenham's comment, I get that in later versions of Windows, ? stands for 0 or 1 characters.
What about FAT short names ?
Now for the tricky parts : What about names with a leading dot (i.e. 0 characters before the first dot) ? What about files with multiple dots ?
Trailing dots are stripped before anything is performed, so the extension of abc.def..... is def, and its base is abc.
The dot is at a fixed position in the short name, and is present even for files without an extension. That's why *.* matches all files, even those without an extension.
Leading dots, multiple dots, extensions of more than 3 characters and base (before the dot) parts of more than 8 characters are invalid in short FAT names (also called DOS names), so a file whose long name (displayed under Windows) is one of those will have a made-up short name, looking like POBASE~N.POE, where :
POBASE is a part of the base (usually the beginning, stripped of unusual characters),
~ is a literal tilde character,
N is a single or multiple-digit number, and is usually the smallest number that doesn't clash with existing names,
POE is a part of the extension (usually the beginning, stripped of unusual characters), where the extension is the part after the last dot,
and all the parts are capital letters or digits.
I created the following files, in that order :
.ab had the short name AB~1
a.b.c had the short name AB~1.C
a.bcde had the short name A~1.BCD
a.x y (notice the space) had the short name a.xy
..ab had the short name AB~2, since AB~1 was already there (first example)
a.b, a.b., a.b.., a.b... are all equivalent names for the same file (i.e. to create a.b... will overwrite a.b if it exists).
When you run the command dir ????.* on an old Windows 98 system, the following files will be matched :
AB~1, with long name .ab
AB~1.C, with long name a.b.c
AB~2, with long name ..ab
Now, while Vista and 7 have tried to throw most DOS legacy out of the window (pun intended), there are still some remnants : if you type C:\PROGRA~1 in the address bar of an explorer window, you'll land into (the half-baked localized variant of) C:\Program files, and if you plug in a FAT-formatted USB key, the files will have short names. I'm not sure if the wildcards will match against these short names, but here are some "fun" facts, that show it's not even worth investigating :
Fun facts
In a french version of Windows 7, C:\Program files will show up in explorer as C:\Programmes, but if you try to cd C:\Programmes, it will fail, so the translated names don't seem to be used by the command-line.
On the same Windows 7, ????????.? (8.1 question marks) will match with a.b.c (which is only 5 characters), but anything shorter (like ???????.? with 7.1 question marks) won't match it.
On the same Windows 7, ????????.? will match foo, although there is no dot in foo.
Conclusion
To conclude, if you want to write a program that reliably deletes files with exactly four characters before the first (or last) dot, use some of the other solutions, don't use wildcards.
However, be warned that older windows versions don't have all those fancy-dancy scripting capabilities for getting the length of a string with awkward syntax (I mean, seriously, if "!n:~3,1!" neq "" echo del "%%F", it's nearly as bad as zsh globbing modifiers.
All this would be so much simpler if windows didn't have three layers of file naming (FAT short names, "actual" file name, and translated file name), and if they hadn't chosen to change the meaning of ?.
Sigh
This will delete any file with exactly 4 characters name (excluding extension) and with any extension.
e.g.: del4chrs "C:\DATA\Junk Folder"
#echo off
setlocal enabledelayedexpansion
if "%1" == "" (
echo Usage del4chrs {folder}
goto :eof
)
if not exist "%~1\nul" (
echo Folder not found.
goto :eof
)
pushd "%~1"
for %%F in (????.*) do (
set n=%%~nF
if "!n:~3,1!" neq "" echo del "%%F"
)
I believe this is the simplest solution to delete all files whose base name disregarding extension is exactly 4 characters: EDIT - I removed the mask from the DIR command since FINDSTR is doing the real filtering anyway
for /f "eol=: delims=" %%F in ('dir /b /a-d^|findstr /rx "....\.[^.]* ...."') do del "%%F"
It is easy to modify the solution to only delete files that consist of 4 numeric digits (disregarding extension)
for /f "eol=: delims=" %%F in ('dir /b /a-d^|findstr /rx "[0-9][0-9][0-9][0-9]\.[^.]* [0-9][0-9][0-9][0-9]"') do del "%%F"
Related
I can't seem to write certain characters (inverted question marks, fancy single quote marks, ampersands) to a text file, and then to search that file for those characters. For example the following findstr doesn't find the upside down question mark item in .txt:
#echo off
echo "Cato Event - GO Beyond GDP. What Really Drives the Economy¿">c:\test.txt
findstr /I /N /C:"Cato Event - GO Beyond GDP. What Really Drives the Economy¿" c:\test.txt
pause
::chcp 1254
I've tried with various chcp commands also to no avail.
Any help appreciated.
That is a known issue with FINDSTR - Some characters provided on the command line with ANSI byte codes > 127 are transformed into a different character by FINDSTR, prior to doing the search, which causes the search to fail.
The solution is to put the search string(s) in a file and use the /L and /G options.
See the section titled "Character limits for command line parameters - Extended ASCII transformation" at What are the undocumented features and limitations of the Windows FINDSTR command?
The only other option (assuming you want to stick with native batch commands) is to use FIND instead. It has much less functionality, but it does not have the character translation issue, and I believe it should work for your simple literal search.
find /I /N "Cato Event - GO Beyond GDP. What Really Drives the Economy¿" c:\test.txt
The line numbers at the beginning of each matching line will look like [123] instead of 123:.
I've noticed when using DIR in windows command line for one particular case wildcards don't function as I'd expect. Example:
dir *.doc
runs similar to
dir *.doc*
I've only noticed this behavior when the wildcard directory precedes the period (which is an important and frequent case). Whats even stranger is if you run either:
dir *.d
dir *.do
It will execute as expected. It's only once you hit 3 character extensions the strange behavior starts. I mentioned it runs similar to the command above because if the contents after the *. is not the extension it will not return the file. E.g.:
dir *.tar
will not return file.tar.gz but will return file.targa
Why is this and how can it be avoided?
The DIR command matches against both long and short names.
Windows file names that do not meet the old 8.3 DOS standard are automatically given a short file name alias that does meet the standard. (This can be disabled on NTFS drives)
For example, a file with a name of "file.targa" is assigned a short name of "file~1.tar" on my local hard drive. The rules for the short name are undocumented, and the assigned name varies depending on what names already exist within the folder when the file is created. But one thing that is consistent is that long extensions are truncated to the first three characters of the long extension.
Given that DIR searches both long and short names, you can now see that "*.tar" matches "file~1.tar" which is the short name for "file.targa"
This issue exists for pretty much every command that performs uses wild card file masks, including FOR, COPY, MOVE, REN, etc.
Workarounds
If your volume is NTFS, then you (or your administrator) can disable short names. But existing short names persist, it only disables generation of short names for future files. This is not a very practical solution, since you may not be in a position to know if any short file names exist.
If you simply need a list of files, without the other DIR info, then you can pipe the result of DIR /B through FINDSTR to get the desired result.
dir /b *.tar | findstr /le ".tar"
The extension is the part after the last dot. Anything before the last dot is the filename, including dots as ordinary characters.
Also remember that dir matches short and long names.
I don't really have a very deep understanding of what I'm doing here but the thing is I cant make it work for just certain file type
FOR %%2 in (*.mp4,*.avi,*mkv) do set fname=%%~n2
FOR %%1 in (*.srt,*.sub) do (
attrib -r %1
PING 1.1.1.1 -n 1 -w 1000 > NUL
cscript "NewReplace.vbs" %1
ren %1 "%fname%".srt
)
So what it DOES is that this is located into %appdata%\Microsoft\Windows\SendTo and when I Right Click-Send to-MyBatch it searches for a MP4, AVI, MKV in the clicked file directory, copies it's name to my file and appends .srt.
What I WANT IT to do is only accept .srt and .sub files, and when it copies the name to append the original extension not always .srt.
Fundamentally, FOR %%2... and similar are errors.
The metavariable (loop-control variable - you've attempted to use 2) must be alphabets and that alphabetic character is case-sensitive (one of the few placs in batch that exhibits case-sensitivity.)
When referencing the value within a for loop, use %%x (where x is your chosen metavariable.)
%n where n is 1..9 means the parameter n provided to the routine, hence %1 means 'the first parameter given to this routine,' so thisroutine something somethingelse would see something as parameter 1 and somethingelse as parameter 2, referenced by %1 and %2 respectively.
Your first line, when corrected, will assign the name part of each filename found in turn from the selected masks (*.mp4,*.avi,*mkv) and the name part of the very last such name found will be assigned to the variable fname.
Similarly, your second for loop will look for all .srt and .sub files, remove any read-only attribute, wait, run your cscript with the entire name (name+extension) of the *.srt or *.sub found, then attempt to rename that file to the name found in the first loop.srt - because that is what you've specified.
The upshot of all this is that the first loop will locate zzz.mkv (if that is the last filename found in the first loop) and assign zzz to fname.
The second loop will rename the first .srt or .sub file found to zzz.srt and since that filename now exists, will fail to rename all of the remaining .srt and .sub files - including zzz.srt.
That's what your code, when the metavariables are fixed, should try to do. It probably isn't what you want it to do, but you've not provided an example, and you've not clearly explained what to do if there are multiple (*.mp4,*.avi,*mkv) files or what your cscript is supposed to do when provided with a filename, or what you want to do about srt and sub files
By using the command from a folder in D: drive
for /f "delims=" %%d in ('cd') do set pathdrv=%%d
echo %pathdrv%
I get "d:\some folder".I want to write batch commands to create autorun file in the root of the drive. Please help me to strip the drive letter "d:" so the output is "\some folder" and what extra change do i do to strip "\".
Short answer: Use the substring syntax to strip the first two characters from the %cd% pseudo-variable:
%cd:~2%
To remove the first backslash too:
%cd:~3%
This reliably works even with Unicode paths when the console window is set to raster fonts.
Longer answer, detailing some more options (none of which work well enough):
For arguments to the batch file you can use the special syntax %p1, which gives you the path of the first argument given to a batch file (see this answer).
This doesn't work the same way with environment variables but there are two tricks you can employ:
Use a subroutine:
call :foo "%cd%"
...
goto :eof
:foo
set result=%~p1
goto :eof
Subroutines can have arguments, just like batch files.
Use for:
for %%d in ("%cd%") do set mypath=%%~pd
However, both variants don't work when
The console is set to "Raster fonts" instead of a TrueType font such as Lucida Console or Consolas.
The current directory contains Unicode characters
That have no representation in the current legacy codepage (for Western cultures, CJK is a good choice that doesn't fit). Remember that in this case you'll only get question marks instead of the characters.
The problem with this is that whil environment variables can hold Unicode just fine you'll get into problems once you try setting up a command line which sets them. Every option detailed above relies on output of some kind before the commands are executed. This has the problem that Unicode isn't preserved but replaced by ?. The only exception is the substring variant at the very start of this answer which retains Unicode characters in the path even with raster fonts.
Drive letter:
%CD:~0,1%
Full drive name (incl. colon):
%CD:~0,2%
The following is a batch script that calls mp3splt (a program that splits mp3s http://mp3splt.sourceforge.net/mp3splt_page/home.php) into partitions of 5 mins long.
for /f %%a IN ('dir /b *.mp3') do call c:\PROGRA~1\mp3splt\mp3splt -t 5.0 -o output\#f+-+#n+-+#t %%a
It breaks when the mp3 files contain a space. Can anyone propose a workaround?
for %%a IN (*.mp3) do (
call c:\PROGRA~1\mp3splt\mp3splt -t 5.0 -o output\#f+-+#n+-+#t "%%a"
)
What others are saying here to quote the variable is doubtless correct. That's needed for it to work correctly. But it also is only half the solution.
Your problem here is that dir /b spits out lines of text, each one containing a single file name, like so:
foo bar.mp3
baz gak.mp3
track01.mp3
...
for /f on the other hand is made for reading files or something else (the dir output in this case) line by line ... but it also does tokenizing. That means it splits strings at configurable places into individual tokens.
By default, /F passes the first blank
separated token from each line of each
file. Blank lines are skipped. You
can override the default parsing
behavior by specifying the optional
"options" parameter. This is a quoted
string which contains one or more
keywords to specify different parsing
options. —help for
So you only get the part before the first space of the file name. You can work around that by using
for /f "delims=" in ...
to specify that tokenizing should be done with no delimiters, essentially giving you the complete line each time. But a better way is actually the one I outlined at the start to just use the regular for to iterate over the files. No surprises with spaces in file names there and it actually makes your intent a lot clearer.
I am regularly surprised why people tend to choose a convoluted and wrong solution over a simple, clear and correct one.
You can quote the variable containing the file name:
"%%a"