Запуск MacOS в терминале, который по сути является BSD, поэтому я размещаю свой вопрос здесь, а не на askdifferent. Я хочу обрезать свой набор данных изображений на последующих этапах, удаляя файлы случайным образом. В некоторых каталогах более 1 миллиона jpg. Мои данные находятся в главном каталоге с подкаталогами, максимальная глубина которых составляет всего 1:
-master
-data1
image.jpgs
-data2
image.jpgs
-data3
image.jpgs
-data4
image.jpgs
... and so forth
Я нашел эту ссылку:
https://superuser.com/questions/1186350/удалить-все-кроме-1000-случайных-файлов-в-каталоге
... и придумал:
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
для sort
и tail
необходимы, так как входные данные разделены нулем. Ни один из них не будет жаловаться, если строк меньше 50000 — sort
ему все равно, и tail
он ничего не выведет, так как после 50000-й строки ничего нет. rm
может жаловаться на запуск без аргументов, но -r
параметр GNU xargs
предотвратит его запуск, rm
если он не получит входных данных (BSD xargs в этом не нуждается, но, вероятно, не будет жаловаться).
Наконец, но самое важное, -z
опция для ввода с разделителями-нулями, вероятно, не будет поддерживаться BSD tail. Вам понадобится GNU tail, который можно установить с помощью homebrew.
Вероятно, вы могли бы обойтись без строк, разделенных нулем, если бы гарантированно не содержали в своих именах файлов пробелы, символы новой строки, кавычки, обратные косые черты и т. д. В этом случае:
for d in */; do find "$d" -type f | sort -R | tail -n +50001 | xargs rm; done