我正在编写一个简单的方法来批量移动文件,并尝试了两种方法:
#(1)
find . -name '*.pdf' | xargs -I{} mkdir pdfs; mv {} pdfs
#(2)
find . -name '*.pdf' -exec mv {} pdfs \+
第一种方法“有时”出人意料地有效,但是,在多次删除包含 pdf 的文件夹并将 pdf 返回到父目录后,它突然停止工作。
它会产生以下错误:
mv: rename {} to pdfs: No such file or directory
xargs: unterminated quote
而第二种方法会出现以下错误:
find: -exec: no terminating ";" or "+"
更新:
我让它与:
find . -name '*.pdf' -exec mv "{}" pdfs \;
但是,如果我想在一行中创建目录并移动文件,这将不起作用,例如:
find . -name '*.csv' -exec mkdir -p csvs && mv "{}" csvs \;
查找:-exec:没有终止“;”或“+”
如何实现目录的创建和移动?
答案1
假设您的情况确实如此简单(文件以 .pdf 结尾),一个简单的
mv -- **/*.pdf pdfs/
会做。
对于 zsh,**
默认情况下启用递归 glob,对于 bash,您必须首先使用 启用它shopt -s globstar
。
我怀疑您的 find 调用实际上可能稍微复杂一些。但特别是如果您使用 zsh,您的 shell 的扩展通配符功能非常强大,并且通常可以让您免去记住每次都有效的正确 magic find 参数的麻烦;)
答案2
像这样的东西应该有效:
$ touch foo.pdf white\ space.pdf
$ ls
foo.pdf 'white space.pdf'
$ mkdir pdfs && \
find . -path ./pdfs -prune \
-o -name '*.pdf' -exec mv {} pdfs/ \;
$ tree
.
└── pdfs
├── foo.pdf
└── white space.pdf
- 这将创建目录
pdfs
,并且仅在成功创建后才继续。 - 这会查找以 结尾的所有文件,
.pdf
同时确保它与已移动到pdfs
目录的文件不匹配(该-path pdfs -prune
部分会跳过此目录中的文件)。 - 这做
mv
每场比赛执行一次。使用mv -t pdfs/ {} \+
(GNU 扩展)来提高性能。
答案3
不带引号的命令将命令与命令;
分开,因此不可能起作用。mv
find
迄今为止最简单的解决方案是在运行之前创建目标目录find
。如果你不想保留空目录,可以rmdir
稍后再保留;如果目录包含任何文件,这将失败。
如果您有 GNU mv
,它有一个-t
选项可以让您方便地在要移动的文件之前命名目标目录,以便您可以说
mkdir pdfs
find . -name '*.pdf' -exec mv -t pdfs {} +
rmdir pdfs || true
如果你没有mv -t
,请尝试类似的方法
find . -name '*.pdf' -exec sh -c 'mv "$@" "$0"' pdfs {} +
我们无耻地使用“zeroth”参数来sh -c
将目标目录名称与参数列表分开传递"$@"
。 (按照惯例,这个“第 0 个”参数将包含 shell 的名称,但由于这对这里的任何内容都没有用,并且字符串无论如何都必须包含某些内容,因此我们可以进行一些修改,这样我们就不必处理参数列表.)
find ... -exec mv {} pdfs \;
可以工作,但效率有些低,因为它mv
为每个找到的文件运行一个单独的命令。+
终止符表示-exec
为尽可能多的文件运行单个子进程(类似于xargs
),但要求{}
令牌位于最后。
答案4
一种方法是,使用珀尔的rename
:
touch foo.pdf white\ space.pdf $'new\nline.pdf'
find . -name '*pdf' -print0 | rename -n -0 's|[^/]+\.pdf$|./pdfs/$&|ms'
-n
当尝试令人满意时放弃。