How can I get the "dir" and "copy" commands to operate on "*.xyz" but not "*.xyz~"?
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