通过排除查找和移动

通过排除查找和移动

我需要同时使用 find 和 mv

要求:需要找到所有文件*.xml但排除deposit.xml并将其移动到另一个文件夹(相当简单)

我的尝试:

mv `find ./*.xml '!' -type d | fgrep -v deposit.xml` ./Archive

如果有任何文件,这工作得很好,如果不存在文件,则会抛出以下错误

mv: missing destination file operand after `./Archive'
Try `mv --help' for more information.*

答案1

解析lsor的输出通常是一个坏主意find,因为您无法区分哪些字符是文件名的一部分以及哪些字符是分隔符。如果您不控制文件名,这可能是一个安全漏洞,允许攻击者伪造文件名,导致您的脚本执行任意代码。看为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?。不过,在您的情况下可能没问题,特别是当您的文件似乎是某种源代码树时,文件名通常不带“异国情调”字符,特别是不带空格。

尽管如此,使用强大的命令实际上并不困难。核心思想是进行find调用mv而不是解析find.以下命令.xml以递归方式从当前目录和子目录移动:

find . ! -type d -name '*.xml' ! -name deposit.xml -exec mv {} ./Archive \;

为了稍微加快速度,您可以mv通过运行中间 shell 对 的调用进行分组。

find . ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +

如果您只想从当前目录移动文件,而不遍历子目录,那么您需要指示find不要递归。如果您的find实现支持该-maxdepth选项:

find . -maxdepth 1 ! -type d -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +

否则:

find . -name . -o -type d -prune -o -name '*.xml' ! -name deposit.xml -exec sh -c 'mv "$@" "$0"' ./Archive {} +

如果您的 shell 是 ksh,则可以使用它的扩展 glob。这比使用 更容易find,但便携性较差。移动当前目录中的文件:

mv !(deposit).xml Archive/

在 ksh93 中,也可以从子目录移动文件:

set -o globstar
mv **/!(deposit).xml Archive/

在 bash 中,您!(…)也可以使用该模式,但您需要shopt -s extglob先运行。要使用该**/模式,您需要shopt -s globstar先运行,并且要注意,直到 bash 4.2,**/除了目录之外,还会遍历目录的符号链接。

shopt -s extglob globstar
mv **/!(deposit).xml Archive/

!(…)在 zsh 中,您可以在运行后使用该模式setopt ksh_glob。或者,您可以在运行后使用 zsh 的语法setopt extended_glob。无论哪种方式都可以使用递归遍历语法。

setopt extglob
mv **/(^deposit).xml Archive/

答案2

使用“查找”命令:

find ./*.xml -type f ! -name "deposit.xml" -exec mv {} ./Archive ';'

将“find”与“xargs”命令一起使用:

find ./*.xml -type f ! -name "deposit.xml" | xargs -I {} mv {} ./Archive

使用“for”循环和“find”命令。

for f in $(find ./*.xml -type f ! -name "deposit.xml"); do mv ${f} ./Archive; done

另外,根据GNU/Linux 系统的联机帮助页,“mv”命令具有“-t | --target-directory”选项。所以你应该能够将它与“xargs”一起使用,如下所示:

find ./*.xml -type f ! -name "deposit.xml" | xargs mv -t ./Archive

我还没有测试过,因为我使用的是 FreeBSD 系统。

答案3

问题是您不想显示错误消息,或者您不想在没有 .xml 的情况下运行该命令?

在第一种情况下重定向输出2>/dev/null并且不会显示错误消息。

在第二种情况下运行

for i in $(find ./*.xml '!' -type d | fgrep -v deposit.xml);do mv $i ./Archive;done

答案4

find . ! -name "deposit.xml" -name "*.xml" -exec mv {} ./temp \;

find 有 -exec 选项,使用它我们可以使用结果文件作为操作数执行命令并使用 '! -name' 选项来排除文件。

相关内容