How can I get the "dir" and "copy" commands to operate on "*.xyz" but not "*.xyz~"?
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~
?
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:
-
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.
-
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. -
Use
xcopy
. Whilexcopy
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
-
Use
robocopy
. Whilerobocopy
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~
-
Use
for
,dir
andfindstr
in an appropriate combination. This essentially just filters out all lines that have a~
at the end and operates on the rest. Theif
variant above was more elegant, I think.for /f "usebackq delims=" %i in (`dir /b *.txt ^| findstr /r "[^~]$"`) do @copy "%i" foo
-
Just for completeness: PowerShell:
Copy-Item *.txt foo
My solution was to execute del *.xyz~
prior to my copy *.xyz
. Not brilliant, but it works.