我有一个备份脚本,可以删除超过 x 天的备份。
在 Linux 机器上,此方法运行良好:
find /backups/dummy-prod-db -name "*_D_dummy-prod-db*" -type f -mtime +7 -exec rm -v {} \;
但是如果我在装有 Cygwin 的 Windows 机器上运行这个程序:
c:\cygwin64\bin\find.exe "C:\\backups\\dummy-prod-db\\" -name "*_D_dummy-prod-db*" -type f -mtime +7 -exec rm -v {} \;
它返回
/usr/bin/find: missing argument to `-exec'
我该如何修复它?
编辑:
我在 Windows 上使用 CMD shell。
答案1
作为你已经发现了,解决方法是使用;
而不是\;
。在我的回答中,我将尝试解释这背后的机制。
首先,了解为什么\;
在 Linux 上需要 是件好事。这并不明显,但find
在 Linux 上, 之后的某个地方需要;
(或+
) 作为参数-exec
,而不是\;
;请参阅来自 The Open Group 的规范,它表示-exec utility_name [argument ...] ;
。反斜杠是为 shell 准备的。问题是;
是 shell 所特有的,它是一个命令终止符。如果您使用;
,shell 会将其解释为这样,find
根本看不到它。要告诉 shell;
不应特殊处理,我们可以使用反斜杠 ( \;
) 对其进行转义,也可以将其括起来 (";"
或';'
)。shell 将解释并删除反斜杠或引号,并将find
看到;
它所期望的唯一内容。
您使用的路径c:\cygwin64\bin\find.exe
让我相信您不是在 Cygwin 中的 Bash(或类似的 shell)中工作,而是在 中工作cmd.exe
。cmd.exe
;
不是特殊的,因此无需对其进行转义。此外,\
不是转义字符(^
是)。\;
您使用的 got tofind.exe
字面上是\;
。该工具未找到;
(也没有+
)它所期望的 ,因此出现错误。Sole;
到达find.exe
as ;
,这就是该工具所期望的。
据我所知";"
,cmd.exe
最终应该会变成find.exe
这样,因为;
.";"
在 Linux 上也能正常工作,所以我们可以";"
在这个问题的上下文中称之为“通用语法”。注意不是通用的,单引号在*';'
中不是特殊的。cmd.exe
* 情况稍微复杂一些。
在 Linux 中,可执行文件像 一样find
将其参数作为数组获取(在您的情况下:find
,/backups/dummy-prod-db
,-name
,*_D_dummy-prod-db*
,-type
,f
,-mtime
,+7
,-exec
,,) 。 shell 处理单词拆分和通配符(rm
虽然在您的情况下没有未加引号的通配符),它会删除引号、反斜杠。-v
{}
;
在 Windows 中,可执行文件(如)find.exe
将其参数作为单个细绳据我所知,在 Windows 系统调用 之前main()
,它会_setargv()
调用 将命令行解析为标准 Cargc
和argv[]
传递给main()
程序函数的参数。程序可以提供自己的_setargv()
。这意味着对引号和通配符(如 )的解释*
以及拆分为单词(单独的参数)实际上是每个可执行文件的工作,而不是cmd.exe
。可执行文件可能使用一些标准_setargv()
,那么它几乎就像cmd.exe
完成了工作,这种情况类似于 Linux 中的情况;或者它可能提供自己的_setargv()
。
我写作的地方
";"
cmd.exe
最终应该find.exe
达到;
“最终” 表示“之后_setargv()
”。_setargv()
引号与命令字符串的其余部分一起出现;如果find.exe
提供了自定义的_setargv()
,它可以以作者希望的任何方式解释这些引号。
我写道
单引号不是特殊符号
cmd.exe
我的意思其实是“不特别适用于常用的_setargv()
”。如果find.exe
提供了一个自定义的_setargv()
,它可以以作者想要的任何方式解释单引号,例如像 Bash 中的单引号一样。我不知道,或许你find.exe
确实像这样解释单引号。
一般来说,“某事在…中起作用(或不起作用)cmd.exe
”包括cmd.exe
和一些标准_setargv()
。
相比之下:在 Windows 中(FIND
本机FIND
不是*nix 的一个移植版本find
)有其独特的语法,因为它对所获取字符串的解释与任何标准都不同_setargv()
。您可以在此处找到更多信息:Tcler 的 Wiki / 执行引号问题(请注意,文章的某些部分是在 Tcl 的背景下进行的,与我们的问题无关,但相关片段仍然FIND
具有教育意义)。
答案2
我在这里找到了答案:
https://stackoverflow.com/a/32377808/1215291
它说末尾的反斜杠应该被删除。我修改了这一点:
... -exec rm -v {} \;
对此:
... -exec rm -v {} ;
并且它起作用了,但我不明白为什么。
如果有人能解释一下我将不胜感激。