4

When I use copy *.txt somefolder\ the system seems to copy all *.txt~ files too, which is not what I want. A similar same effect can be seen with dir:

C:\Users\Paul\Documents\Programs\Proffy>dir *.txt
 Volume in drive C is Vista
 Volume Serial Number is EC23-AD6B

 Directory of C:\Users\Paul\Documents\Programs\Proffy

29/11/2008  13:54            35,821 COPYING.txt
31/10/2009  21:54             1,644 INSTRUCTIONS.txt
06/06/2009  15:57             1,393 INSTRUCTIONS.txt~
04/01/2009  11:59               116 Notes.txt
19/04/2009  16:53               134 README.txt
04/01/2009  12:42               132 README.txt~
31/10/2009  21:30               197 TODO.txt
31/10/2009  19:10               414 TODO.txt~
               8 File(s)         39,851 bytes
               0 Dir(s)  41,938,862,080 bytes free

C:\Users\Paul\Documents\Programs\Proffy>

How can I get dir and copy to only operate on files that end with .txt and not .txt~?

1
  • 1
    When I first saw this question, I thought 'yes, that's useful and clear' so I upvoted it. Then I started adding an answer which was coming to the conclusion 'they're treated as special to remind you to rename or delete them'. While I was editing, someone downvoted me, with no comment to explain why. This leaves a nasty taste in my mouth, but I got the message 'help not wanted'.
    – pavium
    Oct 31, 2009 at 22:37

6 Answers 6

5

Apparently the shell considers both the short and the long name for wildcard expansion. Longer explanation can be found in shf301's answer. This is unfortunate and probably a left-over from Ye Olde Days of DOS because that's what cmd is trying to be compatible with—sort of—after all.

Several options here:

  1. Use forfiles, which has a different semantic for wildcard expansion:

    forfiles /m *.txt /c "cmd /c copy @file foo"
    

    This is available at least on Vista and later.

  2. Use for and check the extension:

    for %a in (*.txt) do @if %~xa==.txt @copy "%i" foo
    

    Unfortunately for also returns any files with the .txt~ extension when only using wildcard expansion. That's why we need to check the extension a second time.

  3. Use xcopy. While xcopy has the same semantics for wildcard expansion as the shell you can give it a file with names to ignore:

    echo .txt~>tmpfile
    xcopy *.txt foo /exclude:tmpfile
    del tmpfile
    
  4. Use robocopy. While robocopy has the same semantics for wildcard expansion as the shell you can give it a list of files/wildcards to ignore:

    robocopy . foo *.txt /XF *.txt~
    
  5. Use for, dir and findstr in an appropriate combination. This essentially just filters out all lines that have a ~ at the end and operates on the rest. The if variant above was more elegant, I think.

    for /f "usebackq delims=" %i in (`dir /b *.txt ^| findstr /r "[^~]$"`) do @copy "%i" foo
    
  6. Just for completeness: PowerShell:

    Copy-Item *.txt foo
    
1

My solution was to execute del *.xyz~ prior to my copy *.xyz. Not brilliant, but it works.

3
  • +1. D'oh! Doing things in the right order trumps knowing all the cool commands others offered.
    – beggs
    Nov 1, 2009 at 15:50
  • Well, initially I don't assume people would be willing to throw away files :-)
    – Joey
    Nov 1, 2009 at 21:54
  • This is not a proper answer to your own question, sorry. Brute force file deletion is NOT a solution. Feb 22, 2011 at 17:46
1

I'm not sure how to stop dir/copy from matching only *.txt but I can explain why *.txt returns what it does; it matches the short file name which ends with .txt for all the files, do a dir /x *.txt to see this. This problem occurs for every set of extensions that start with the same first three characters (e.g. *.htm will match htm, html, and even htmlasdfasdf).

Also most every Windows application will act this way because the API the OS provides to search for files FindFirstFile matches the long file names and short files names. To quote:

The search includes the long and short file names.

You'll have to do some sort of custom filtering as Johannes Rössel answer suggested.

0

Since Joey mentioned completeness, I note, as mentioned here, that this varies according to what command interpreter's DIR and COPY commands one uses. The DIR command in Take Command and its COPY command, for examples, only match long names by default and so don't exhibit this behaviour. (Matching of short as well as long names can be turned on for compatibility with CMD's DIR and COPY commands.)

0

The existing answer cover copying files just fell, but not listing them.

You can use the archive bit for both purposes. Although it's intended to be used with XCOPY1, it also works with DIR2.

Steps:

  1. Make sure the archive bit is set for all .txt files:

     ATTRIB +A *.txt
    
  2. Remove the archive bit from all .txt~ files:

     ATTRIB +A *.txt~
    
  3. List all .txt files which have their archive bit set:

     DIR /AA *.txt
    

    or copy them to somefolder:

     XCOPY /A *.txt somefolder/
    

1 XCOPY uses the /A switch to exclude all files which do not have their archive bit set. This can be used to exclude certain files (e.g., temporary files) from daily backups. With the /M switch, it also removes the archive bit from the files, which is handy when copying files to small storage devices (e.g., diskettes). Also, modifying a files automatically sets the archive bit, so the /M switch can be used for incremental backups.

2 DIR /AA shows only files which have their archive attribute set.

-1

you could try: copy "*.txt"

2
  • That's exactly the same as without the quotes. So what should this accomplish?
    – Joey
    Nov 1, 2009 at 0:56
  • It seems like it would disinclude the '~' suffix. Hence me using the phrase "could try."
    – eqzx
    Nov 2, 2009 at 4:39

You must log in to answer this question.

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