Переміщення файлів та запрошення користувача, коли є повторювані імена:
Як показують відповіді 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
і -newermt
), що використовуються для їх повернення значень, або дії (як -print
і -exec
), які часто використовуються для їх побічних ефектів.
Коли жоден оператор (як -a
для і , -o
для чи ) не надається між виразами, -a
мається на увазі. find
використовує оцінку короткого замикання для та та або . (тобто ) є істинним лише в тому випадку, якщо вирази p і q є істинними, тому q не потрібно оцінювати, якщо p є хибним. Хоча ми часто не думаємо про це в цих термінах, саме тому тести повинні бути правдивими для наступних дій або тестів, які повинні бути оцінені. Наприклад, припустимо, виникає каталог. Він оцінюється як хибний, тому він може пропустити все згодом.p q
p -a q
find
-type f
Як і тести, дії також оцінюються як істинні чи помилкові. Таким чином, -exec
звітує, якщо виконана команда завершила успіх у звіті (вірно) або провал (помилка). У нас цей ланцюжок -exec
виразів пов'язаний із неявними та :
-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Це намагається перемістити файл, і якщо mv
повідомлення про помилку, зупиняється. Ми не хочемо попереджати про правильно пропущений файл, якщо якась інша проблема була причиною його не переміщення.
Але якщо це вдалося, то вона працює на [
команду . Мовляв find
, [
підтримує свій вид виразів, переданих як аргументи. [ -f {} ]
перевіряє, чи існує операнд після -f
(переданий йому find
замість {}
) і є звичайним файлом, і повертає або істинний / успішний, або хибний / невдалий.
(Статуси виходу багатьох команд найкраще трактувати як ознаку успіху чи невдачі, але [
існуючий статус, як правило, найкраще тлумачити як істинний або хибний.)
Якщо [
повернуто помилкове значення, файл не зникне, тому його перемістили, тому нічого робити не потрібно. Але якщо [
повернуто помилкове, файл все ще є. Потім find
оцінюється наступний -exec
вираз, який друкує попереджувальне повідомлення.
Подальше читання