【问题标题】:Why does find -exec mv {} ./target/ + not work?为什么 find -exec mv {} ./target/ + 不起作用?
【发布时间】:2011-08-02 05:27:52
【问题描述】:

我想确切地知道{} \;{} \+| xargs ... 做了什么。请用解释澄清这些。

以下 3 个命令运行并输出相同的结果,但第一个命令需要一点时间,格式也略有不同。

find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file

这是因为第一个对来自find 命令的每个文件运行file 命令。所以,基本上它运行为:

file file1.txt
file file2.txt

但后两个 find 使用 -exec 命令对所有文件运行一次文件命令,如下所示:

file file1.txt file2.txt

然后我运行以下命令,第一个运行没有问题,但第二个给出错误消息。

find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'

对于带有{} \+ 的命令,它会给我错误消息

find: missing argument to `-exec'

这是为什么呢?谁能解释一下我做错了什么?

【问题讨论】:

  • 真正的问题很简单,为什么第一个有效而第二个无效? (1)找。 -type f -iname '.cpp' -exec mv {} ./test/ \; (2) 找到 。 -type f -iname '.cpp' -exec mv {} ./test/ \+

标签: linux find cygwin exec


【解决方案1】:
find . -name "*.mp3" -exec mv --target-directory=/home/d0k/Музика/ {} \+

【讨论】:

  • 请在您的答案中添加一些解释,以便其他人可以从中学习
  • 您需要回答问题,该问题要求解释。仅代码不是答案。
【解决方案2】:

对于不支持-inamefind 实现或不支持-tmv 实现,与find -iname ... -exec mv -t dest {} + 等效的标准是使用shell 对参数重新排序:

find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
  exec mv "$@" /dest/dir/' sh {} +

通过使用-name '*.[cC][pP][pP]',我们还避免了依赖当前语言环境来确定cp 的大写版本。

请注意,+,与 ; 不同,在任何 shell 中都不是特殊的,因此不需要引用(尽管引用不会有害,当然除了不支持的 shell,如 rc \ 作为引用运算符)。

/dest/dir/ 中的尾随 / 使得 mv 失败并出现错误,而不是将 foo.cpp 重命名为 /dest/dir 在仅找到一个 cpp 文件而 /dest/dir 没有找到的情况下t 存在或不是目录(或目录的符号链接)。

【讨论】:

  • +1... 作为执行命令的初步操作,在 shell 中操作实际上对各种用例都很有用...很好。
【解决方案3】:

manual page(或online GNU manual)几乎可以解释一切。

find -exec 命令 {} \;

对于每个结果,都会执行command {}。所有出现的{} 都被文件名替换。 ; 以斜线为前缀,以防止 shell 解释它。

find -exec 命令 {} +

每个结果都附加到command 并在之后执行。考虑到命令长度的限制,我猜这个命令可能会执行更多次,手册页支持我:

该命令的总调用次数将远少于匹配文件的数量。

请注意手册页中的这句话:

命令行的构建方式与 xargs 构建其命令行的方式非常相似

这就是为什么{}+ 之间除了空格之外不允许使用任何字符。 + 使 find 检测到参数应该附加到命令中,就像 xargs 一样。

解决办法

幸运的是,mv 的 GNU 实现可以接受目标目录作为参数,使用 -t 或更长的参数 --target。它的用法是:

mv -t target file1 file2 ...

您的find 命令变为:

find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+

来自手册页:

-执行命令;

执行命令;如果返回 0 状态,则为 true。所有以下要查找的参数都被视为命令的参数,直到一个由 `;' 组成的参数遇到。字符串 `{}' 被当前正在处理的文件名替换,它出现在命令的参数中,而不仅仅是在单独的参数中,如在某些版本的 find 中。这两种结构都可能需要转义(使用 `\')或引用以保护它们不被 shell 扩展。有关使用 -exec 选项的示例,请参见示例部分。指定的命令对每个匹配的文件运行一次。该命令在起始目录中执行。使用 -exec 操作存在不可避免的安全问题;您应该改用 -execdir 选项。

-执行命令 {} +

-exec 操作的这个变体在选定的文件上运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;该命令的调用总数将远少于匹配文件的数量。命令行的构建方式与 xargs 构建其命令行的方式非常相似。命令中只允许有一个“{}”实例。该命令在起始目录中执行。

【讨论】:

  • 我实际上知道它是如何工作的,我已经多次阅读这本手册,但是我收到了使用 {} + 的错误消息,虽然适用于 {} \;我在 Windows 中使用 Cygwin。
  • @Shahadat:你读过“来自手册页”之前的部分吗?您已将 ./test/ 放在 {}+ 之间,但它们之间不允许使用非空白字符。
  • 你说我不应该把 ./test/ 放在 {} 和 + 之间。那么 mv 命令将如何工作; mv 需要源是 {},需要目标是 ./test/ 并以 + 终止。你能写出你认为正确的命令吗?
  • @Shahadat:我明白你想要达到的目标。 Windows 执行程序的速度很慢,因此您希望将其组合为一个命令。我将添加一个替代答案。
  • + 命令有点奇怪 AFAIU,因为它将文件粘贴在“末尾”(而不是代替 {})所以为什么要使用 {} - 这很令人困惑.感谢我不知道的-t 选项,似乎该选项是为解决-exec + 问题而创建的!
【解决方案4】:

我在 Mac OSX 上遇到了同样的问题,使用的是 ZSH shell:在这种情况下,mv 没有 -t 选项,所以我不得不找到另一个解决方案。 但是以下命令成功:

find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;

秘诀是引用大括号exec 命令的末尾不需要大括号。

我在 Ubuntu 14.04 下测试(使用 BASHZSH shell),它的工作原理是一样的。

但是,当使用+ 符号时,它似乎确实必须在exec 命令的末尾。

【讨论】:

  • {} 需要在 fishrc shell 中引用,但不能在 zshbash 或 Bourne 或 csh 系列的任何其他 shell 中引用。
  • @StephaneChazelas 是的,在带有bash 的 Ubuntu 下重新测试,确实不需要引号。奇怪的是,如果不在 MacOS 下引用它们(使用 zsh),我遇到了问题。但我手头没有 Mac 可以再试一次...
【解决方案5】:

不,+\; 之间的区别应该颠倒过来。 + 将文件附加到 exec 命令的末尾,然后运行 ​​exec 命令,\; 为每个文件运行命令。

问题是find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ 应该是find . -type f -iname '*.cpp' -exec mv {} ./test/ + 无需转义或终止+

xargs 我很久没用了,但我觉得像 + 一样工作。

【讨论】:

  • 我也试过了,但得到了同样的错误信息。此外,我发现在任何地方都只使用 + 但在我的 cygwin 中我必须使用 \+ 或 "+" 才能工作。
  • 哦,这是一个 cygwin 环境。抱歉,我不知道,我不使用 cygwin shell,我只使用 *nix。
  • @Shahadat Hossain try -name "*.cpp" 我几乎不使用 -iname,除非我想做一些困难的正则表达式搜索,比如 -iname '???work.*\.cpp'
  • @Mike:我想你误解了-iname-name 之间的区别。 -iname-name 的不区分大小写版本,在处理正则表达式方面没有区别。我建议在发布之前尝试命令,您的命令在我的 shell 中也会失败。
  • @Lekensteyn 在您发表评论之前,情况已经确定。我以为在你发帖之前我已经承认了 Shahadat,这是一个简单的“好的”。不,我没有手动运行它,我是从头顶开始运行的,并且很少将这种形式的正则表达式搜索与 find 一起使用。这只是一个“可能有帮助”类型的东西。
猜你喜欢
  • 2019-10-26
  • 2012-08-03
  • 1970-01-01
  • 2021-12-25
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多