As you have already found out, the fix is to use ;
instead of \;
. In my answer I will try to explain the mechanics behind this.
At first it's good to know why you need \;
on Linux. It's not obvious, but find
on Linux expects ;
(or +
) as an argument somewhere after -exec
, not \;
; see the specification from The Open Group, it says -exec utility_name [argument ...] ;
. The backslash is for the shell. The problem is ;
is special for the shell, it's a command terminator. If you used ;
, the shell would interpret it as such, find
wouldn't see it at all. To tell the shell ;
should not be treated specially we can escape it with a backslash (\;
) or we can quote it (";"
or ';'
). The shell will interpret and remove the backslash or the quotes and find
will see sole ;
it expects.
The path c:\cygwin64\bin\find.exe
you used makes me believe you were not working in Bash (or similar shell) in Cygwin, but rather in cmd.exe
. In cmd.exe
;
is not special, so there is no need to escape it. Additionally \
is not an escape character (^
is). \;
you used got to find.exe
literally as \;
. The tool did not find ;
(nor +
) it expected, hence the error. Sole ;
gets to find.exe
as ;
and this is what the tool expects.
AFAIK ";"
in cmd.exe
should ultimately get to find.exe
as ;
. ";"
works on Linux as well, so we can call ";"
"universal syntax" in the context of this problem. Note ';'
is not universal, single-quotes are not special in cmd.exe
*.
* The situation is somewhat more complicated.
In Linux, executables like find
get their arguments as an array (in your case: find
, /backups/dummy-prod-db
, -name
, *_D_dummy-prod-db*
, -type
, f
, -mtime
, +7
, -exec
, rm
, -v
, {}
, ;
). The shell handles word splitting and globbing (in your case there were no unquoted wildcards though), it removes quotes, backslashes.
In Windows, executables like find.exe
get their arguments as a single string. AFAIK technically before the Windows system calls main()
, it calls _setargv()
to parse the command line into the standard C argc
and argv[]
arguments that it passes to the main()
function of the program. The program can provide its own _setargv()
. This means that interpretation of quotes and wildcards like *
, and splitting to words (separate arguments) are really the job of each executable alone, not of cmd.exe
. The executable may use some standard _setargv()
, then it's almost like cmd.exe
did the job, a situation similar to what is in Linux; or it may provide its own _setargv()
.
Where I wrote
";"
incmd.exe
should ultimately get tofind.exe
as;
"ultimately" means "after _setargv()
". Before _setargv()
the quotes were there along with the rest of the command string; if find.exe
provided a custom _setargv()
, it could interpret these quotes in any way the author desired.
And where I wrote
single-quotes are not special in
cmd.exe
I really meant "not special for commonly used _setargv()
". If find.exe
provided a custom _setargv()
, it could interpret single-quotes in any way the author wanted, e.g. like single-quotes in Bash. I don't know, maybe your find.exe
does interpret single-quotes like this.
In general a phrase "something works (or doesn't work) in cmd.exe
" includes cmd.exe
and some standard _setargv()
.
For comparison: FIND
in Windows (the native FIND
, not a port of *nix find
) has its own peculiar syntax because it interprets the string it gets differently than any standard _setargv()
would. You can find more information here: Tcler's Wiki / exec quotes problem (note some parts of the article are in the context of Tcl which has nothing to do with our problem, still the fragment about FIND
is educative).