在本质上是 BSD 的终端中运行 MacOS,因此在这里发布我的问题而不是询问不同。我想通过随机删除文件来在后续步骤中修剪图像数据集。有些目录有超过 100 万张 jpg。我的数据位于主目录中,子目录的最大深度仅为 1:
-master
-data1
image.jpgs
-data2
image.jpgs
-data3
image.jpgs
-data4
image.jpgs
... and so forth
我找到了这个链接:
https://superuser.com/questions/1186350/delete-all-but-1000-random-files-in-a-directory
...并想出了:
for f in *.jpg; do find "$f" -type f -print0 | sort -R | tail -n +50001 | xargs -0 rm; done
虽然它确实有效,但我希望它能够对子目录递归地执行此操作,因此我不必为每个目录手动执行此操作。所以我的问题/要求是:
- 我可以以某种方式优化它以加快速度吗?
- sort/tail 遇到文件少于 50,000 个的目录时会返回错误吗?
答案1
检查了链接的源帖子后,看起来您的循环实际上应该是:
for d in */; do find "$d" -iname '*.jpg' -type f -print0 | sort -zR | tail -zn +50001 | xargs -0r rm; done
从目录运行master
。
和-z
的选项是必需的,因为输入是空分隔的。如果少于 50000 行,两者都不会抱怨 -不关心也不会输出任何内容,因为第 50000 行之后没有任何内容。可能会抱怨在没有参数的情况下运行,但是如果没有输入,GNU 的选项将阻止它运行(BSD xargs 不需要它,但可能不会抱怨)。sort
tail
sort
tail
rm
-r
xargs
rm
最后但最重要的是,-z
BSD tail 可能不支持 null 分隔输入的选项。您需要 GNU tail,它可以使用自制程序安装。
如果你的文件名保证不包含空格、换行符、引号、反斜杠等,那么你可能不需要空分隔行。在这种情况下:
for d in */; do find "$d" -type f | sort -R | tail -n +50001 | xargs rm; done