Как найти файлы между двумя датами, используя «найти»?

21

У меня есть учетная запись электронной почты, которая прошла 60 ГБ писем, и в настоящее время у меня много проблем с использованием почтового клиента для архивирования писем прошлого года (2011).

Через терминал я пытаюсь использовать find для поиска файлов между 2011-01-01 и 2011-12-31, но безрезультатно.

Как я могу найти файлы между двумя датами?

Если это уместно, конечной целью будет пакет, который будет перемещать каждый найденный файл, соответствующий интервалу дат, в папку.

Zuul
источник
@EliahKagan В то время, если память не изменяет, дублированные имена не были проблемой. Тем не менее, если вы сообщаете, что у вас есть время, дополнительная информация по любому заданному вопросу всегда ценится :) Кроме того, я одобрил ваш ответ, поскольку он дает дополнительную информацию по этой теме.
Зуул
@EliahKagan В этом случае, я призываю вас дать ответ с практической отказоустойчивости, которую вы подчеркнули :)
Zuul

Ответы:

16

Вы можете использовать этот скрипт:

#!/bin/bash
for i in $(find Your_Mail_Dir/ -newermt "2011-01-01" ! -newermt "2011-12-31"); do
  mv $i /moved_emails_dir/
done
Октавио Филипе Гонсалвес
источник
6
Вывод findне должен обрабатываться в таком forцикле оболочки , за исключением случаев, когда гарантируется, что ни один файл не имеет пробелов в своем имени. -exec, -execdirили -print0 | xargsобычно должен использоваться вместо; Другое возможное решение, которое, как правило, гораздо менее желательно, но допускает использование forцикла, заключается во временной установке, IFSчтобы пробел не распознавался как разделитель полей.
Элия ​​Каган
@EliahKagan, как будет выглядеть команда: просто заменить findна exec? Не могли бы вы добавить ответ, касающийся использования пробелов? Очень признателен.
SherylHohman
3
@SherylHohman Нет, не используйте execкоманду. Используйте findкоманду с -execдействием для запуска mv, или что вам нужно, как описано в ответе, который я опубликовал . Когда find... -execзапускает вашу команду с путями, которые она нашла, она не использует оболочку, поэтому пробелы не вызывают разбиение слов или глобализацию . (Возможно, вы захотите опубликовать новый вопрос о вашем конкретном случае или точно спросить, что вы хотите знать.)
Элия ​​Каган
@EliahKagan Извините, я неправильно прочитал ваш пост - и это было от вас ! Ты восхитителен! Ваш пост Отличный .. и спасибо за ответ, хотя это была моя собственная ошибка в чтении!
SherylHohman
40

Bash найти файлы между двумя датами:

find . -type f -newermt 2010-10-07 ! -newermt 2014-10-08

Возвращает список файлов с метками времени после 2010-10-07 и до 2014-10-08

Bash найти файлы с 15 минут назад до сих пор:

find . -type f -mmin -15

Возвращает список файлов, которые имеют временные метки после 15 минут назад, но до этого момента.

Bash находит файлы между двумя временными метками:

find . -type f -newermt "2014-10-08 10:17:00" ! -newermt "2014-10-08 10:53:00"

Возвращает файлы с метками времени между 2014-10-08 10:17:00и2014-10-08 10:53:00

Эрик Лещинский
источник
10

Перемещение файлов и запрос пользователя при наличии повторяющихся имен:

Как показывают ответы Subv3rsion и Эрика Лещинского , -newermtпредикат выбирает файлы, измененные более недавно, чем дата (и необязательное время), указанная в качестве его операнда. Найти файлы

  • где-нибудь в srcdir (т. е. включая его подкаталоги, их подкаталоги и т. д.)
  • последнее изменение (например) сентябрь 2014
  • и переместить их вdestdir

...Вы можете запустить:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;

В -execвыражении find передает имя файла, найденное вместо {}. ;означает, -execчто команда, которую нужно выполнить, и ее аргументы все были предоставлены (в случае, если последующие выражения передаются для поиска после -execаргументов этого конкретного предиката - пример этого см. ниже). ;должен быть экранирован, \;так как это не интерпретируется специально оболочкой. (Без \, ;завершит всю findкоманду, работая так же, как перевод строки. Даже если эта findкоманда не имеет ничего после этого -execвыражения, неудача в передаче ;аргумента по-прежнему является синтаксической ошибкой.)

Если вы просто хотите перечислить файлы - что целесообразно, если вы не уверены, как хранятся старые электронные письма или какие другие файлы могут присутствовать - пропустите -execи все справа от него. (Для электронной почты часто электронные письма с разными датами хранятся в одном и том же файле; для тех, кто находится в ситуации, описанной в приведенном здесь вопросе, я рекомендую выяснить, как они хранятся, прежде чем перемещать какие-либо файлы.) Если вы хотите напечатать свои имена и переместить их, добавь -printраньше -exec.

mv -i подсказки в любое время, когда файл будет перезаписан в месте назначения, например, если:

  • файл с таким же именем существует из предыдущей резервной копии, или
  • файл с тем же именем, но из другого подкаталога srcdirуже был перемещен во время той же findоперации, или
  • (наименее вероятно) файл с таким же именем был создан где-то во srcdirвремя той же findоперации, после того, как оригинал был перемещен, но достаточно быстро, чтобы его можно было найти после findпрохождения через другой подкаталог.

Другие способы вызова rm :

У вас есть другие варианты обработки файлов с повторяющимися именами.

  • Без -i(т. Е. ) Обычно не запрашивает подтверждения, но делает это, если файл назначения доступен только для чтения. (mv {} destdir/mvmv может даже преуспеть в перезаписи файла, доступного только для чтения, иногда, например, если пользователь, выполняющий его, владеет файлом.)
  • Если вы не хотите даже такой степени интерактивности и хотите mvвсегда (пытаться) перезаписать файлы с одинаковыми именами, используйтеmv -f .
  • Если, напротив, вы хотите пропустить исходные файлы, когда уже существует целевой файл с таким именем, используйте mv -n.
  • mvпринимает -bи --backupфлаги автоматически переименовывать файлы с одинаковыми именами , которые уже существуют в месте назначения. По умолчанию ~добавляется для создания имени резервной копии, и если файл с именем и файл с именем резервной копии уже существуют в месте назначения, файл резервной копии будет перезаписан. Это значение по умолчанию может быть переопределено параметрами, передаваемыми при вызове mv, и переменными среды. Смотрите man mvподробности и пример ниже.

Перемещение файлов и создание резервных копий в случае дублирования имен:

Чтобы переместить все файлы , выполнить резервное копирование файлов с повторяющимися именами с использованием ~суффикса и использовать пронумерованные суффиксы, когда файлы уже существуют (чтобы избежать перезаписи), выполните:.~n~.~

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;

Если вы пропустили файлы с повторяющимися именами и хотите узнать, какие из них:

Если вы используете mv -nи хотите знать, какие файлы не были перемещены, потому что там был другой файл с таким же именем, возможно, лучше всего просто снова выполнить исходную findкоманду без -execи все справа от нее. Это напечатает их имена.
Он также будет печатать имена любых соответствующих файлов, созданных после того, как вы выполнили исходную find .... -exec ...команду, но для этого приложения, как правило, их не будет, так как вы ищете файлы со старым временем модификации. Можно дать файлу временную метку модификации старше его реального возраста с помощью touchи других механизмов, но это вряд ли произойдет в этом случае без вашего ведома.

Зная сразу же, как файлы пропускаются из-за повторяющихся имен:

mv -nне сообщает и не возвращает никакого специального кода выхода , когда он воздерживается от перемещения файла. Поэтому, если вы хотите, чтобы вас сразу же информировали о пропущенных файлах во время выполнения find, вам придется сделать для этого отдельный шаг. Одним из способов является:

find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -n {} destdir/ \; \
    -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \; 

Несколько, вероятно, незначительных технических соображений: это предупреждает неправильно, если mvне удается скопировать файл по причине, отличной от существующей в месте назначения, и выходит из отчета об успешном завершении . Это кажется маловероятным, но я не уверен, что это невозможно. Кроме того, он потенциально страдает от состояния гонки : он предупреждает об отсутствии реальной ошибки, если новый файл с тем же именем был создан в том же месте в течение очень короткого времени после перемещения старого файла и до проверки на посмотрим, был ли он удален. (Рассматривая приложение, я сомневаюсь, что любая из этих проблем вообще когда-либо возникнет.) Она может быть переписана для проверки пункта назначения доперемещая файл вместо после: тогда условие гонки будет относиться к вновь созданным файлам назначения вместо исходных файлов. И хотя ошибки и предупреждения, о которых сообщают findили mv(или [, хотя их не должно быть), будут записываться в стандартную ошибку , наше ...skipped (exists in...предупреждение записывается в стандартный вывод . Обычно оба появляются на вашем терминале, но это может иметь значение, если вы пишете сценарий.

Я разбил эту команду на две строки для удобства чтения. Это может быть выполнено таким образом, или вы можете удалить \и новую строку (т.е. разрыв строки).

Как работает эта findкоманда?

findПредикаты могут быть тестами (например, -typeand -newermt), используемыми для их возвращаемых значений, или действиями (like -printи -exec), которые часто используются для их побочных эффектов.

Если между выражениями не указан оператор (например, -afor и , -ofor или ), -aподразумевается. findиспользует оценку короткого замыкания для и и или или . (т.е. ) имеет значение true, только если выражения p и q оба имеют значение true, поэтому q не нужно оценивать, если p равно false. Хотя мы часто не думаем об этом в этих терминах, именно поэтому тесты должны быть верными для последующих действий или тестов, которые будут оцениваться. Например, предположим, что он попадает в каталог. Он оценивается как ложный, поэтому он может пропустить все потом.p qp -a qfind-type f

Подобно тестам, действия также оцениваются как истинные или ложные. Таким образом, -execсообщает, если выполненная команда вышла из отчета об успехе (true) или сбое (false). У нас есть эта цепочка -execвыражений, связанных с неявными и :

-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;

Это пытается переместить файл, и, если mvсообщает об ошибке, останавливается. Мы не хотим предупреждать о правильно пропущенном файле, если по какой-то другой причине он не был перемещен.

Но если это удалось, то она работает на [команду . Как find, [поддерживает свой собственный вид выражений , передаваемые в качестве аргументов. [ -f {} ]проверяет, существует ли операнд после -f(переданный ему findвместо {}) (и является ли он обычным файлом), и возвращает либо истину / успех, либо ложь / сбой.
(Статусы выхода многих команд лучше всего интерпретировать как означающие успех или неудачу, но [существующий статус обычно лучше всего интерпретировать как истина или ложь.)

Если [возвращено значение false, файл исчезает, поэтому он был перемещен, поэтому не нужно ничего делать. Но если [возвращается false, файл все еще там. Затем findоценивает следующее -execвыражение, которое печатает предупреждение.

Дальнейшее чтение

Элия ​​Каган
источник
Когда я получаю время, я надеюсь , добавить раздел о соображениях производительности и -exec ... +с mv -t, в ближайшее время .
Элия ​​Каган,