5

I was just trying to check a dump-directory for any ZIP programs like PeaZip, NanoZip, etc. and ran into an odd problem that I have seen only a few times before.

I used the following command to list files whose filenames contain zip (e.g., nanozip.zip, peazip2.rar, winzip-beta.exe, etc.):

dir *zip*

This listed any files whose filenames contain zip, but also all files with a .zip extension (e.g., foobar.zip).

I then tried the following:

dir *zip*.*

This gave the same results.

Does anyone know of a way to get the expected results? (I know that for may be able to do it, but the output won’t be correct.)

9
  • You said you're looking for any programs with zip in the name. If that's the case and I haven't misunderstood your objective, why isn't it sufficient to do the obvious and just add the .exe extension to your pattern, e.g., dir *zip*.exe. Commented Dec 3, 2012 at 17:40
  • Yes, I was looking for programs when I ran into this scenario, but not all programs are executable. My example clearly showed that the files could be .rar, .zip, .exe, etc. hence the title and question specifically asking about files.
    – Synetech
    Commented Dec 3, 2012 at 17:41
  • AFAIK the cmd.exe pattern matching simply won't support what you want. It isn't that great.
    – Zoredache
    Commented Dec 3, 2012 at 17:42
  • Okay, so are you looking for any names that contain zip except in the extension? Commented Dec 3, 2012 at 17:42
  • @Zoredache, it is a strange shortcoming. ☹
    – Synetech
    Commented Dec 3, 2012 at 17:42

8 Answers 8

2

Problem

Listing all files that have zip in the basename (before the last dot, if any) is tricky because of two reasons:

  • Windows only has two wildcards: * and ?.

    * matches any number of characters (including zero).

    ? matches exactly one character (except for the dot), unless it's the last character of the pattern, followed by a dot, only other wildcards or only other wildcards and then a dot.1

  • There are no actual extension in long filenames. The GUI might treat everything that follows the last dot as the file's extension, but that's just a convention.

    To make matters worse, . has a special meaning on the command prompt. Before LFN, every file had an extension (although it could be empty). Therefore, *.* matched all files, while * matched only files with an empty extension.

    To maintain some backward compatibility, . is ignored if it's followed only by wildcards and other dots, except if the dots are adjacent and followed by at least one wildcard or if there's no wildcard at all and at most a single asterisk before the dot.1

Examples:

  • foo?.bar will match the file foo.bar, but foo?bar won't match neither foobar nor foo.bar.

  • *, *.*, *.*., *.*.* and **. will match all files in any given folder, while *., *.. and *..* won't.

Workaround

Unless you're using the archive bit to perform incremental backups2, there's a way to display the files you're interested in (and only those), using only DIR and the ATTRIB command.

Steps:

  1. First, set the archive bit on all files that contain zip anywhere in their respective filenames:

     ATTRIB +A *zip*
    
  2. Now, unset the archive bit on all files with a zip extension:

     ATTRIB -A *.zip
    

    If you want to exclude files whose respective extensions end with zip as well (e.g., ezip), use the following command instead:

     ATTRIB -A *.*zip
    

    Since *.*zip will get tested against the 8.3 filenames as well, this will also match files whose respective extensions begin with zip (e.g., zipx), unless the 8.3 filenames aren't present or have been altered.

  3. Since the previous command unset the archive bit on files like nanozip.zip, reset those:

     ATTRIB +A *zip*.*zip
    
  4. Now, you can use the /AA switch of the DIR command to show only files with a set archive bit:

     DIR /AA *zip*
    

With the /S switch on DIR and the /S [/D] switch on ATTRIB, this even works for files in subdirectories.


1 This is intended as a list of quirks, rather than an exhaustive explanation of wildcard behavior.

2 Windows XP's NTBackup, e.g., respects the archive bit.

2
  • Hmm, I must have missed your answer. That’s a clever trick. I actually do not (nor have ever) used the archive bit (I believe it is mostly a holdover from old DOS days), so this trick might actually be a reasonable workaround. It makes sense to target the extension, essentially “hide” them, target the remaining ones, then restore. I smell a batch-script project coming on… ☺ unless the 8.3 filenames aren't present or have been altered. I always leave 8.3 active and only manually modify the occasional filename to remove non-ASCII characters so that Norton DiskEdit doesn’t complain ;-).
    – Synetech
    Commented Dec 14, 2012 at 17:48
  • I assumed as much. You got three answers that day, and two of them were rather large. Yes, the archive bit is barely used anymore. The last desktop version of Windows that let you alter the archive bit from the GUI was XP, if I'm not mistaken. It was also the last version that came with NTBackup, which makes use of the archive bit for incremental backups.
    – Dennis
    Commented Dec 14, 2012 at 18:46
0

Not a nice one, but working one..

dir | findstr ini..*

dots are used as regular expression, means any character and * from 0 to infinite times

Only downside is that it doesn't mach files withou extension.

5
  • Like the for command, that too won’t work because it strips all of the other information like the volume name, serial-number, total bytes, free bytes, etc.
    – Synetech
    Commented Dec 3, 2012 at 17:59
  • 1
    I suppose you meant dir | findstr zip..*, but the problem (besides the omitted lines) is that this matches File.zipx and File.izipx also (as per the OP, "they can have zip (in this case) in the extension as well, so long as they have it in the filename").
    – Karan
    Commented Dec 3, 2012 at 19:13
  • @Karan: You used quotes — “they can have zip … in the extension as well, …” Who/what are you quoting? I don’t see this statement anywhere else on this page. Commented Dec 3, 2012 at 22:59
  • @Scott: Expand all the comments to the question itself and look carefully - I quoted the OP since those are his requirements.
    – Karan
    Commented Dec 3, 2012 at 23:04
  • @Karan: Oops! I missed the hidden comments. Commented Dec 3, 2012 at 23:07
0

If you're willing to "eyeball" then use

dir /OE *zip*

which will sort the output by extension and can visually ignore those with a .zip extension - they will be all grouped together.

For a list you can examine, massage, etc. send the output to file:

dir /OE *zip* > myzip.txt

6
  • I’m not sure how that would help. The /O switch without parameters defaults to sorting by filename (i.e., equal to /on). The incorrect items (e.g., foobar.zip) would still be interspersed with the legitimate items.
    – Synetech
    Commented Dec 3, 2012 at 18:01
  • Yes, the switch should be /OE
    – user168261
    Commented Dec 3, 2012 at 18:09
  • Unfortunately even with /oe, it would still require too much manual “eyeballing” since the legitimate files would be interspersed with the incorrect ones (e.g., nanaozip.zip would be somewhere in between nabble.zip and quargle.zip—for example). Granted, it would make it a little easier since the out-of-place entries will be fewer this way, but it’s still more blech-y than it should.:-D I’ll give this a +1 because even if the wrong entries are in the middle (e.g., dir /oe noo), it still makes it at least a little bit easier.
    – Synetech
    Commented Dec 3, 2012 at 18:21
  • @Synetech: I had to read your comment twice before I understood that your point was that you want to include files that have ZIP in their filename, even if they also have ZIP in their extension (a subtle point that I don’t see spelled out in your question), and therefore, for example, answers like dir | findstr /i /v /r "\..*zip" would not be acceptable. (It might have been clearer if you had said, “since a very few legitimate files would be interspersed with the incorrect ones.”) Commented Dec 3, 2012 at 22:53
  • @Synetech: (continued) The obvious response is: Execute darkphader’s answer (or my findstr /v "\..*zip"), and then do dir *zip*zip*. I assume you don’t have any files that have ZIP in the extension twice. :) Commented Dec 3, 2012 at 22:55
0

Try:

dir * | findstr /i zip.*\.

leave out the /i if you want a case sensitive search

5
  • This strips out all of the other stuff that dir shows like volume name, serial-number, total size, free space, etc. It defeats the point to using dir. Also, it doesn’t list any files that have no extension (e.g., blahzip), which means it misses most directories as well.
    – Synetech
    Commented Dec 3, 2012 at 18:53
  • This also omits files without an extension.
    – Karan
    Commented Dec 3, 2012 at 18:56
  • Basically then line by line filtering of the output of the "dir" command for the desired information would need to skip the first 7 lines to accomplish what you want - you'll need a bit more scripting.
    – user168261
    Commented Dec 3, 2012 at 19:05
  • Also neither the ls command via cygwin nor the dir command in powershell supply the same header info as the dir command.
    – user168261
    Commented Dec 3, 2012 at 19:09
  • …or footer. ☹​​
    – Synetech
    Commented Dec 3, 2012 at 19:56
0

Similar to week's solution above:

dir | findstr /e zip.*.[a-z]* 

This should find anything that contains "zip", followed by any number of characters, followed by a "." and any number of letters, followed by the end of the filename. Did I miss anything else?

5
  • 2
    That would fail to show nanozip.zip.
    – Dennis
    Commented Dec 3, 2012 at 18:15
  • True. I'll edit the above to make allowances for that.
    – Llamanerds
    Commented Dec 3, 2012 at 18:22
  • Okay, I'm new here. What's the protocol for correcting an answer? For now I've just struck it through. Should I delete the incorrect answer?
    – Llamanerds
    Commented Dec 3, 2012 at 18:31
  • Changing/deleting incorrect parts of an answer is OK. You should use Markdown instead of HTML. In Markdown, * is used to italicize.
    – Dennis
    Commented Dec 3, 2012 at 18:48
  • This incorrectly matches File.zipx and File.izipx as well, besides omitting the extra lines from a normal dir output.
    – Karan
    Commented Dec 3, 2012 at 19:14
0

For testing, these are some valid file names I used (i.e. those having "zip" somewhere in the filename, with extension not mattering):

zip
has zip
has zip text
zip.doc
textzip.txt
File.zip.txt
File - zip text.zip
this file name haszipin it.txt

Invalid file names:

noname
File.xzip
File.zipx
File.azipx
File.bxzip
File name.zip

Given all the above, and a lack of support for both the "|" (or) and "+" (one or more) in findstr, I believe what you're looking for cannot be done using out of the box Windows utils only. Also, while the other dir output lines such as those containing "volume" or "directory" or "bytes" can be included, using find or findstr to filter the output of dir automatically means that the matching file and directory count will be incorrect (it will show the files and directories dir originally found, not the ones finally displayed after filtering). The total matching file size will naturally be incorrect as well for the same reason, although the bytes free will be correct as that does not depend on the results returned.

This might be possible using a convoluted batch or PowerShell script, but really, at that point you might as well code your own program in C or similar.

5
  • Yup, that’s the dilemma. The dir command seems to have a bug (or at best a sever syntacitcal shortcoming) that prevents a simple task from working. Granted, exist tools that can provide directory listings, but I really don’t like using third-party tools with their vastly different output. I am used to the output format of dir and even rely on it in some cases (for example, comparing directory listings). ☹
    – Synetech
    Commented Dec 3, 2012 at 19:55
  • Unless someone manages to crack this somehow, I don't believe a simple solution for this is possible without using 3rd party utils, so I think you might have no choice here - either live with the restriction or find a better dir replacement.
    – Karan
    Commented Dec 3, 2012 at 19:57
  • Even if you redirect the complete directory listing to a file and use a regex-supporting utility (say Notepad++) to remove all non-matching files, you'll still have the problem with the file/dir number and size (in dir's footer). So basically, the filtering needs to be done by the dir listing utility itself, rather than filtering later.
    – Karan
    Commented Dec 3, 2012 at 20:00
  • Actually, I have already looked for a dir replacement. Unfortunately I have yet to find a good one (in fact, I have seen few in general; most tend to be GUIs that let you save a list to file instead of console tools). :-(
    – Synetech
    Commented Dec 3, 2012 at 21:30
  • I'll let you know if I find something that fits the bill. Meanwhile, here's a blog post by Raymond Chen about wildcards in DOS. Also, I'd be interested in knowing whether the type of matching you're looking for (i.e. searching for a string like "zip" in the filename only and not the extension) is possible even with Advanced Query Syntax in Windows.
    – Karan
    Commented Dec 3, 2012 at 23:20
0

This batch file should work for you.

If you run it with no command line arguments it will give a listing like:

"dir *zip*.*"

but it will filter out files that do not contain "zip" in the "name" portion of the filename (ignores the extension). I assumed that a filename that contains "zip" in the name AND extension is a valid match, like:

somezipfile.zip

If you run it with an argument (like txt or "txt" or "any text") it will do the same except using the specified argument instead of "zip".

This batch file will also display the correct file count and file size summary.

Please let me know if it is not doing what you need.

@echo off



set "zfind=%~1"
if "%zfind%."=="." set "zfind=zip"

set "zpattern=*%zfind%*.*"
set "zhold="
set zcount=0
set zgotbslash=0



for %%f in ("%zpattern%") do call :work1 "%%~nf" "%%~xf"



if NOT %zcount% EQU 0 goto :start2

rem no matches. look for something that "for sure" won't be found.
set zhold="<[nothing]>"
goto start2



:start2
set "zrandom=%random%.%random%.%random%.%random%.tmp"
if exist "%zrandom%" del "%zrandom%" >nul 2>&1
dir %zhold%>>"%zrandom%" 2>>&1



for /f "usebackq delims=" %%f in ("%zrandom%") do call :work2 "%%~f"



echo.
if exist "%zrandom%" del "%zrandom%" >nul 2>&1
goto :cleanexit



:work1

set "znam=%~1"
set "zext=%~2"



for /f "usebackq delims=" %%g in (`echo set "ztest=%%znam:%zfind%=%%"`) do %%g



rem if "%ztest%" equals "%znam%" then 
rem file "name" did NOT contain the search text.. skip it

if "%ztest%."=="%znam%." goto :work1skip
goto :work1match



:work1match
rem got a match

set zhold=%zhold% "%znam%%zext%"
set /A zcount=zcount+1
goto :EOF



:work1skip
rem skip this one

goto :EOF



:work2

set "zline=%~1"

rem if we already printed the " Directory of d:..." line then:
if %zgotbslash% EQU 1 goto :work2part2

rem looking for "\"
call :testbslash
if %zres% EQU 1 goto :work2gotbslash


echo %zline%
goto :EOF



:work2gotbslash
set zgotbslash=1
echo.
echo %zline%
echo.
goto :EOF



:work2part2
call :testbslash
if %zres% EQU 0 echo %zline%
goto :EOF



:testbslash
set zres=1
set "ztest=%zline:\=%"
if "%ztest%."=="%zline%." set zres=0
goto :EOF




:cleanexit

set "zcount="
set "zext="
set "zfind="
set "zgotbslash="
set "zhold="
set "zline="
set "znam="
set "zpattern="
set "zrandom="
set "zres="
set "ztest="
goto :EOF
-1

There's no good reason to use cmd.exe these days. PowerShell:

dir | ? {$_.BaseName.Contains('zip')}
4
  • That is not an answer to the question asked. I am well aware of PowerShell (and don’t like it in the least for numerous reasons). Besides, there are plenty of programs that can provide a directory listing, so if I wanted to use another program instead of the command-prompt, then I would just use one of those. Finally, the output from dir in PS is completely different than that of the command-prompt, so like I said in the question, it is not an option anyway.
    – Synetech
    Commented Dec 11, 2012 at 15:08
  • @Synetech, it sounds like you are lamenting the fact that something that is old and broken is old and broken but you don't want to change to anything better.
    – dangph
    Commented Dec 11, 2012 at 22:10
  • Wrong no all counts. If it were as bad as you claim, then they would no longer include it in Windows, yet they do. Just because it has a bug doesn’t mean that it is old, nor broken. PS is by no means a be-all, end-all perfect, drop-in, absolute replacement for the command-prompt and expecting everybody to be forced to switch to it is absurd. Moreover, PowerShell is not a replacement for the command-prompt at all; it is a compltely different thing that is merely similar. If you think that PS is “cmd+” or what the command-prompt is goign to be replaced with, then you misunderstand its purpose.
    – Synetech
    Commented Dec 11, 2012 at 23:52
  • @Synetech, they can't get rid of it because people still use it. And there are a lot of BAT files out there. Why do you want to know your disk free space every time you do a dir? Are you afraid of running out of space on your floppy disks? I've been using PS as a command-line shell for ages. It works really well. It even works better than the Unix shells. What would you say its purpose is?
    – dangph
    Commented Dec 12, 2012 at 0:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .