我正在目录列表中搜索某些文件,并且我想删除该文件所在的目录。
这就是我正在尝试的:
find /converter/storage/unmatched/ -size -4b -name '*.mp3' -execdir mv -b `dirname {}` /converter/storage/smallfiles/ \;
mv: cannot move `.' to `/converter/storage/smallfiles/.'
我首先尝试移动它,只是为了向自己证明这可以在不丢弃非预期文件的情况下完成。如何移动或删除包含目录?
答案1
由于以下几个原因,您的命令将无法按预期工作:
bash 评估
`dirname {}`
前find 命令被执行。dirname
可以通过调用 bash 来评估命令的输出来解决此问题-execdir
执行命令之前对找到的文件目录的更改。因此,即使使用正确的语法,也
dirname {}
始终是.
。由于 find 会遍历所有目录内的所有文件(而不是目录本身),因此移动当前正在处理的目录可能会导致意外行为。
我不太清楚如何详细说明,但下面的例子应该可以说明这一点。
$ find data -type f -printf " %p" ; echo data/1/b data/1/a data/2/b data/2/a $ $ find data -type f -exec bash -c ' \ > echo -n " "mv `dirname {}` backup/ > ' \; ; echo mv data/1 backup/ mv data/1 backup/ mv data/2 backup/ mv data/2 backup/ $ $ find data -type f -exec bash -c ' > echo -n " "mv `dirname {}` backup/; mv `dirname "{}"` backup/ > ' \; ; echo mv data/1 backup/ mv data/1 backup/ mv: cannot stat `data/1': No such file or directory
移动目录 后
data/1
, find 继续处理其内容。这会导致出现错误消息,因为 findmv
会对 中的每个文件执行data/1
,但除此之外运行正常。当它完成处理 时data/1
, find 不知何故“丢失”了。虽然 find 可以正确处理所有可能具有特殊含义的字符(如果
{}
作为 find 的普通参数出现),但如果路径中出现空格,则示例 3 中的命令将无法正确执行。为了避免这种情况,dirname
必须将的参数输出都用引号引起来。使用
mv "`dirname "{}"`"
(或mv "$("{}")"
,更易于辨认)可以很好地处理空格,但通常会导致灾难性的后果1。mv -b
无法备份目录,只能备份文件。
正如你自己发现的,问题 3 只会在你尝试移动目录,但如果您删除它则不会。因此,问题 3(在此过程中修复问题 5)的一个简单而安全的解决方案是将匹配的目录移动到 zip 文件中。2
{}
问题 4 可以通过将其作为参数传递给 bash 并以 方式访问来解决$0
。
命令
find /converter/storage/unmatched/ -type f -size -4b -name '*.mp3' \ -exec bash -c ' \
zip -0mqr smallfiles.zip "$(dirname "$0")"\
' {} \;
将按预期工作,尽管在尝试多次移动目录时仍会生成错误消息。
一种更干净的方法(即没有错误消息)是find -depth -type d
浏览目录本身。3
对于每个目录,我们可以使用
find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit
打印1当且仅当应该删除它时4,并测试([
)以检查是否找到打印1。
命令
find /converter/storage/unmatched/ -depth -type d -exec bash -c ' \
[ $(find "$0" -maxdepth 1 -type f -size -4b -name '*.mp3' -printf 1 -quit) ] \
&& echo zip -0mqr smallfiles.zip "$0"\
' {} \;
才会达到预期的效果。
1如果目录名称无与伦比例如,由一个换行符组成,"$(dirname "{}")"
将计算为unmatched
并将$(dirname {})
计算为.
(即,您从中执行命令的文件夹)!
2如果文件很大,即使不压缩文件,这也比直接移动文件花费的时间要长得多。由于目标文件夹名为小文件,我认为这不会是个问题。
3 -depth` 开关使 find 在处理目录本身之前先处理每个目录的内容。这避免了我们在使用第一种方法时收到的错误消息。
4开关-quit
使查找在找到第一个匹配项后停止。这不是绝对必要的,但它可能会加快一点速度。