Перемещение файлов и запрос пользователя при наличии повторяющихся имен:
Как показывают ответы 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/
mv
mv
может даже преуспеть в перезаписи файла, доступного только для чтения, иногда, например, если пользователь, выполняющий его, владеет файлом.)
- Если вы не хотите даже такой степени интерактивности и хотите
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
Предикаты могут быть тестами (например, -type
and -newermt
), используемыми для их возвращаемых значений, или действиями (like -print
и -exec
), которые часто используются для их побочных эффектов.
Если между выражениями не указан оператор (например, -a
for и , -o
for или ), -a
подразумевается. find
использует оценку короткого замыкания для и и или или . (т.е. ) имеет значение true, только если выражения p и q оба имеют значение true, поэтому q не нужно оценивать, если p равно false. Хотя мы часто не думаем об этом в этих терминах, именно поэтому тесты должны быть верными для последующих действий или тестов, которые будут оцениваться. Например, предположим, что он попадает в каталог. Он оценивается как ложный, поэтому он может пропустить все потом.p q
p -a q
find
-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
выражение, которое печатает предупреждение.
Дальнейшее чтение