Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.)

share|improve this question
    
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. –  Nicole Hamilton Dec 3 '12 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 Dec 3 '12 at 17:41
    
AFAIK the cmd.exe pattern matching simply won't support what you want. It isn't that great. –  Zoredache Dec 3 '12 at 17:42
    
Okay, so are you looking for any names that contain zip except in the extension? –  Nicole Hamilton Dec 3 '12 at 17:42
    
@Zoredache, it is a strange shortcoming. ☹ –  Synetech Dec 3 '12 at 17:42

8 Answers 8

up vote 2 down vote accepted

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.

share|improve this answer
    
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 Dec 14 '12 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. –  sudo Dec 14 '12 at 18:46

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.

share|improve this answer
    
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 Dec 3 '12 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 Dec 3 '12 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. –  Scott Dec 3 '12 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 Dec 3 '12 at 23:04
    
@Karan: Oops! I missed the hidden comments. –  Scott Dec 3 '12 at 23:07

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

share|improve this answer
    
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 Dec 3 '12 at 18:01
    
Yes, the switch should be /OE –  user168261 Dec 3 '12 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 Dec 3 '12 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.”) –  Scott Dec 3 '12 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. :) –  Scott Dec 3 '12 at 22:55

Try:

dir * | findstr /i zip.*\.

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

share|improve this answer
    
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 Dec 3 '12 at 18:53
    
This also omits files without an extension. –  Karan Dec 3 '12 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 Dec 3 '12 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 Dec 3 '12 at 19:09
    
…or footer. ☹​​ –  Synetech Dec 3 '12 at 19:56

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?

share|improve this answer
2  
That would fail to show nanozip.zip. –  sudo Dec 3 '12 at 18:15
    
True. I'll edit the above to make allowances for that. –  Llamanerds Dec 3 '12 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 Dec 3 '12 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. –  sudo Dec 3 '12 at 18:48
    
This incorrectly matches File.zipx and File.izipx as well, besides omitting the extra lines from a normal dir output. –  Karan Dec 3 '12 at 19:14

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.

share|improve this answer
    
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 Dec 3 '12 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 Dec 3 '12 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 Dec 3 '12 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 Dec 3 '12 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 Dec 3 '12 at 23:20

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
share|improve this answer

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

dir | ? {$_.BaseName.Contains('zip')}
share|improve this answer
    
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 Dec 11 '12 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 Dec 11 '12 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 Dec 11 '12 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 Dec 12 '12 at 0:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.