Як не допустити `mv` переміщення колекції файлів у єдиний звичайний?


17

Щойно дурною помилкою я лише втратив невелику частину своєї аудіоколекції. :-(
ГЛАДНО У мене була досить недавна резервна копія, але вона все ще дратувала. Окрім вашого справді, інший винуватець, який робив лихоліття mv, виявив наступне:

Звукові файли мали певну схему:

ARTIST - Some Title YY.mp3

де YYє двозначний специфікація року.

mkdir 90<invisible control character>

(До цього моменту я не знав, що насправді я набрав третину зайвого символу, який був невидимим ...!)
Замість того, щоб мати все в одному каталозі, я хотів, щоб усі музики 1990-х були в одному каталозі. Тому я набрав:

find . -name '* 9?.mp3' -exec mv {} 90 \;

Не так складно зрозуміти, що сталося, а? : ->
Результатом (катастрофічним) був порожній каталог незайманих під назвою "90 щось " ( дещо було "невидимим" символом керування) та один єдиний файл під назвою "90", перезаписаний n разів.

ВСІ ФАЙЛИ БУЛИ ОСТАННІ. : - ((очевидно)

Хотів mvби вчасно перевірити, чи не починається підпис цільового "файлу" (пам'ятайте в * NIX: Everything Is A File ) з d------(наприклад drwxr-xr-x). І, звичайно, чи взагалі існує місце призначення . Існує варіант вищезазначеного сценарію, коли ви просто забули в mkdirдиректорію першим. (але, звичайно, ви припускали, що він є там ...)

Навіть наша ОС, що ненавидить домашніх тварин, починаючи з великої літери . Вам навіть буде запропоновано вказати тип призначення (файл? Каталог?), Якщо ви попросите його.

Отже, мені цікаво, чи нам * NIXers все-таки доводиться писати собі « mvскриплет» тільки для того, щоб уникнути подібних видів найбільш небажаних сюрпризів.


2
Не всі файли зникли. Принаймні один .mp3повинен бути там із ім'ям 90, це могло бути таке, на яке у вас не було резервної копії.
Антон

2
Хе, у вас цинічне почуття гумору, ви горіх! :-P Ну, це був файл, званий "єдиним файлом" жирним шрифтом у моїй ОП. :)
синтаксичний помилок

2
mvТут не проблема, технічно це не знає, що ви переміщуєте серію файлів. Ви працюєте mvодин раз для кожного файлу. Ось як find -exec ;працює. Якби ви використовували find -exec +(як у деяких коментарях) , кричали mv б , як тільки отримали більше одного аргументу.
Ітан Рейснер

Хоча запуск mvдля кожного окремого файлу спочатку може здатися трохи менш продуманим, він (як я вже говорив раніше) буде єдиним розумним рішенням, коли вихідні файли будуть розкидані між різними підкаталогами. Те, що в моєму тестовому випадку всі вихідні файли були в одному каталозі, не означає, що це мій фактичний тестовий випадок. Насправді це просто спрощення, тому що пізніше я можу легко розробити це самостійно. Крім того, це робить питання менш трудомісткими для читання через скорочення. :)
syntaxerror

Чому ви розраховуєте mvвимагати існування пункту призначення? mv oldfile newfileце спосіб перейменувати файл, і нерозумно сподіватися newfileна те, що він уже існує та буде каталогом.
Бармар

Відповіді:


37

Ви можете додати /до пункту призначення, якщо хочете перемістити файли в каталог. Якщо каталог не існує, ви отримаєте помилку:

mv somefile somedir/
mv: cannot move ‘somefile’ to ‘somedir/’: Not a directory

Якщо каталог існує, він переміщує файл у цей каталог.


4
Дуже дякую! То тоді повинно бути моє майбутнє життя. Я у вас в боргу. (Як і замітка, мій друг зробив ту саму помилку кілька років тому, тому я відчуваю, що я не один.)
syntaxerror

1
Також при використанні певних оболонок у вас є опція Tab для автоматичного заповнення імен файлів для вас. Якщо я не можу повністю запам’ятати ім’я каталогів і не хочу безладу, як у вас недавно, просто введіть символ або два імені каталогу та HIT TAB . Тоді ви можете бути впевнені, що він існує, тому що автоматичне завершення поклало його туди ....
Andyz Smith

@AndyzSmith Ну, це саме те. Ви можете назвати мою звичку використовувати будь-коли лише використання TAB для складних каталогів або шляхів, але не для 2-літерних типів. :) Але подумайте про це ... можливо, я б і справді повинен розглянути останній випадок відтепер.
синтаксис-помилка

20

У GNU coreutils mvвже є опція, яка вказує, що ви хочете перейти до каталогу: -t/ --target-directory. Якщо аргументу на цю опцію не існує, mvбуде скаржитися замість того, щоб переміщувати всі ваші файли до одного імені файлу.

Я написав би ваше рушій так:

find . -name '* 9?.mp3' -exec mv -t 90 {} +

Зверніть увагу на використання +замість того \;, щоб глобувати якомога більше імен файлів разом, що призводить до швидшого виконання.


Спасибі. (Сподіваюсь, що це знову не одна з цих GNU-
Isms

2
@синтаксична помилка. Це GNUism. POSIXly:find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Стефан Шазелас

Дуже дякую за цей самий SNEAKY однолінійний! Просто подумай, що це +5 я тобі дав. :) Зробить багато спроб проб і помилок непотрібними .--- І ви занадто добре знаєте, чому я зробив це зауваження. Просто потрібно бути на машині, яка прямо POSIX (не трапляється надто рідко), і у мене буде наступна проблема саме там. :)
синтаксеррор

1
@syntaxerror Якщо ця відповідь вирішує вашу проблему, будь ласка, знайдіть хвилину і натисніть прапорець під підрахунком голосів ліворуч, це означатиме всім, що ваша проблема вирішена, і це спосіб висловлення подяки на сайті. Я бачив, що лише деякі ваші інші відповіді на запитання прийняли відповіді, ви також можете розкрити їх.
Антон

Ні, це просто мета. Я часто чекав кілька тижнів, а іноді і 2 місяці, поки не прийму відповідь. Причина полягає в тому, що деякі дуже обізнані люди мають ДУЖЕ завантажений графік, і вони можуть знайти час, щоб дати свої (як правило, найкращі) відповіді через пару тижнів. Тому я завжди вважаю просто поважним чекати, коли вони зупиняться. Ну, і якщо вони насправді цього не роблять, я точно не вагаюся, якщо поставити прапорець точно. Крім того, я не бачу, чому деякі люди завжди так поспішають на SE + його аромати. Легко це зробити, хлопці. Не стрибайте пістолет. :) Це не ваш начальник на вас.
синтаксичний помилок

10

Крім того, якщо ви, як правило, плануєте уникати випадкових перезаписів у майбутньому, є -iможливість mv. Я особисто не можу придумати жодних недоліків, якщо ви

alias mv='mv -i'

Якщо вам потім потрібно щось перезаписати, просто передайте -fваріант.

Псевдоніми набувають чинності лише в тому випадку, якщо ви введете команду безпосередньо в інтерактивну оболонку, а не для випадків, таких як виклик find. Ви могли бігти

find . -name '* 9?.mp3' -exec mv -i {} 90 \;

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


4
Або - як ви, мабуть, не знали - замість цього введіть ´ \ mv ` mv. Цей менш відомий "трюк" призведе до того, що команда з попередньою косою рисою буде ігнорувати будь-які визначення псевдоніму.
синтаксичний помилок

Звичайно, якщо ви справді говорите про це find ... -exec mv ..., вам потрібно буде створити ~/bin/mv(чи якийсь інший відповідний каталог) і зробити це /bin/mv -i "$@"- бо find ... -execне дивиться на псевдоніми.
G-Man каже: "Відновіть Моніку"

У цьому випадку я вважаю за краще env mv. Менше набирати текст. :) Оскільки мій локальний розклад клавіатури вимагає натискання клавіші SHIFT для перекидання вперед, я завжди віддаю перевагу версії "без косої риски" (якщо це застосовується).
синтаксичний помилок

1
@syntaxerror: BTW, коли ви відповідаєте на коментар (у новому коментарі), умовно згадувати ім’я автора, яке передує "@", як у "@ G-Man". Таким чином я отримую сповіщення. (Мені вдалося відповісти на ваш останній коментар напів своєчасно, тому що мені надійшло повідомлення від коментаря Дженні Д.) Ви можете скоротити або використовувати ціле ім’я (без пробілів), наприклад, "@ StéphaneChazelas". Автор публікації автоматично повідомляється про коментарі до цієї публікації. Див відповівши в коментарі пунктів цій сторінці довідки .
G-Man каже: "Відновіть Моніку"

1
Вибачте, що за день я був без Інтернету. @ G-Man Я погоджуюся з тим, що мати особисту версію mvв місці розташування на початку $PATHбуло б більш чистим рішенням. З іншого боку, в основному мені трапляється mvнедбало в інтерактивній оболонці (бо це відбувається швидко). В той момент я складаю що - то більш складне, як findабо forцикл, або навіть сценарій оболонки, я , як правило, виконати деякі сухі пробіги ( з допомогою echo) , щоб гарантувати , що я не порушую що - то. У тих випадках мені не потрібна рука mv, тому що я вже вкладаю в неї деякі думки.
ayekat

7

На додаток до відмінних відповідей вище, я хотів би пояснити, чому у вас не виникло питання про те, переміщувати файли чи ні.

Якщо ви перемістите один файл до нового імені, а це ім’я не є каталогом, mvперейменуйте ваш файл на нове ім'я.

Проблема тут полягає в тому, що ви використовували findдля виконання mvодин раз на файл , а не один раз для всіх файлів .

Якщо б, натомість, ви це зробили mv *90.mp3 90, то mvне вдалося б повідомити про помилку, що "цільовий файл - це не каталог".

Ще одна порада - використовувати заповнення вкладки під час введення цільового шляху. Він покаже, чи є цільовим каталогом додавання /до імені цілі. Ви також mv -iможете запитати, чи хочете ви перезаписати наявний файл.


Якщо б замість цього ви зробили mv *90.mp3 90, то mv не вдалося б зі повідомленням про помилку, що "цільовий файл - це не каталог". Так, чому так складно? Я використовую вашу лінію і буду радий. Тільки в цьому банальному випадку. :) Оскільки це звичайний спосіб, я задаю свої запитання: я б їх звузив заради простоти. Ніхто не заперечував проти findцього, вважаючи, що файли 90-х також можуть бути розкидані по різних підкаталогах, які я також хочу "зловити". Якщо і лише якщо вони завжди знаходяться в одному вихідному каталозі, ваш mvрядок застосовується.
синтаксичний помилок

@syntaxerror Дуже вірно - я мав на увазі це як приклад того, як mvсебе поводити, а не як критику вашого вибору інструментів.
Дженні Д

1
Ви, напевно, могли б створити щось, що поєднує, findі mv, наприклад, find /music -type d -exec mv {}/*90.mp3 targetdir\;- але зараз я відчуваю, що я надмірно ускладнюю це, і просто використовую -iабо -tє більш ефективним
Jenny D

1
@Jenny: Якби ваш find . -type d -exec mv {}/*9?.mp3 target \;приклад працював, все одно існував би ризик, що mvкоманда буде виглядати як mv file targetдля кожного каталогу, що містить лише один *9?.mp3файл; тому всі подібні файли (крім останнього) будуть втрачені.
G-Man каже: "Відновіть Моніку"

4
@syntaxerror: Я аплодую вашим зусиллям викрити істотну частину вашої проблеми, а не весь сценарій 42000 рядків, в якому вона виникає. Але, навіть якщо ви хочете щось зробити для всіх *.mp3файлів у дереві каталогів, ви можете, shopt -s globstarа потім запустити свою команду далі **/*.mp3- **воля буде діяти як a find.
G-Man каже: "Відновіть Моніку"

1

Як альтернативна стратегія загального призначення, я хотів би запропонувати перетворити цю операцію у тимчасовий сценарій. Я вважаю за краще дивитись на результати findта перетворювати їх на mvкоманду вручну, гарантуючи, що я розумію, що я роблю, перш ніж виконати. напр.

find . -name '* 9?.mp3' > tmp
vim tmp

Тепер я можу переглянути список імен файлів і переписати вміст файлу у вигляді команди оболонки.

  • Вміст файлу помістіть в один рядок: ggVGJ
  • Доплатити: Imv [esc]
  • Додайте: Asomedir/ [esc]
  • Збережіть файл. Прочитайте ще раз. Подихати.
  • Виконати source tmpв командному рядку.

Це консервативна стратегія, але мене занадто часто кусають неправильно введені команди -execабо sedкоманди, або неправильно зрозумілі розширення оболонок, і я віддаю перевагу повільному послідовному підходу.

Іншими словами: я занадто боягузливий, щоб використовувати -exec.


1
Ви залишили цей :%s/.*/"&"/крок - адже в цьому випадку ви знаєте, що кожне ім’я файлу містить принаймні один пробіл.
G-Man каже: "Відновіть Моніку"

1
Це укусить вас, якщо назви файлів містять пробіли чи інші спеціальні символи. Їх потрібно цитувати правильно. Перегляд списку команд не особливо сприймає помилки. Є набагато кращі способи перегляду команд перед їх запуском, наприклад, запуску echo mvзамість mv, а потім видалення, echoякщо ви задоволені.
Жил 'ТАК - перестань бути злим'

Виявлення помилки, як імена файлів з пробілами, саме в цьому допоможе ця техніка :-)
Том Різ,

0

Ще один варіант:

-n, --no-clobber не перезаписує існуючий файл

це те саме, що і -і, але він не запитає, він вийде з ладу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.