Как запретить `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: Все это файл ) начинается с d------(например drwxr-xr-x). И, конечно же , является ли адресат существует вообще. Существует вариант вышеупомянутого сценария, когда вы просто забыли вmkdir директорию первым. (но, конечно, вы предположили, что это там ...)

Даже наша ОС животное-ненависть , начиная с капиталом W Имеет ли это сделать. Вы даже получаете запрос указать тип места назначения (файл? Каталог?), Если вы попросите об этом.

Следовательно, мне интересно, если мы * NIXers все еще должны написать себе « mvскриптлет», просто чтобы избежать подобных нежелательных сюрпризов.

синтаксическая ошибка
источник
2
Не все файлы пропали. По крайней мере, один .mp3должен быть там с именем 90, это может быть тот, для которого у вас не было резервной копии.
Антон
2
Хех, у тебя циничное чувство юмора, ты псих! :-P Ну, это был файл, названный «один файл», выделенный жирным шрифтом в моем OP. :)
syntaxerror
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

Если каталог существует, он перемещает файл в этот каталог.

Marco
источник
4
Спасибо огромное! Это должно быть моим будущим спасателем. Я твой должник. (Как примечание, мой друг совершил ту же ошибку несколько лет назад, поэтому я чувствую, что я не одинок.)
syntaxerror
1
Кроме того, при использовании определенных оболочек у вас есть опция Tab для автоматического заполнения имен файлов для вас. Если я не могу вспомнить имя каталога и не хочу беспорядка, как у вас недавно, просто введите символ или два имени каталога и HIT TAB . Тогда вы можете быть уверены, что оно существует, потому что автозаполнение поместило его туда ...
Andyz Smith
@AndyzSmith Ну, это самое. Вы можете назвать моей привычкой использовать TAB только для сложных каталогов или путей, но не для двухбуквенных. :) Но подумайте об этом ... возможно, мне действительно следует рассмотреть и последний случай. впредь.
синтаксическая ошибка
20

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

Я бы написал ваш двигатель следующим образом:

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

Обратите внимание на использование +вместо того \;, чтобы объединять как можно больше имен файлов, что приводит к более быстрому выполнению.

Энтон
источник
Благодарю. (Надеюсь, что это снова не один из этих GNU-измов.)
syntaxerror
2
@синтаксическая ошибка. Это GNUism. POSIXly:find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Стефан Шазелас
Большое спасибо за этот самый SNEAKY один вкладыш! Просто подумай, что это +5, что я тебе дал. :) Будут делать ненужные попытки проб и ошибок. И вы слишком хорошо знаете, почему я сделал это замечание. Просто нужно быть на машине с прямым POSIX (это случается не так уж и редко), и у меня сразу же возникнет следующая проблема. :)
syntaxerror
1
@syntaxerror Если этот ответ решит вашу проблему, пожалуйста, найдите минутку и нажмите на галочку под подсчетом голосов слева, это будет означать, что ваша проблема была решена и это способ выражения благодарности на сайте. Я видел, что только на некоторые другие ваши вопросы с ответами были приняты ответы, возможно, вы тоже захотите их почитать.
Антон
Нет, это просто цель. Я часто жду несколько недель, а иногда и 2 месяца, пока не приму ответ. Причина в том, что некоторые очень хорошо осведомленные люди имеют ОЧЕНЬ загруженный график и могут найти время, чтобы дать свой (обычно лучший) ответ через пару недель. Поэтому я всегда нахожу вежливым ожидание, когда они остановятся. Ну, а если они действительно этого не сделают, я, без сомнения, обязательно нажму на галочку. Кроме того, я не понимаю, почему некоторые люди так спешат на SE + с его вкусами. Полегче, ребята. Не прыгай пистолет. :) Это не твой босс, давящий на тебя.
синтаксическая ошибка
10

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

alias mv='mv -i'

Если вам нужно что-то перезаписать, просто пропустите -fопцию.

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

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

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

ayekat
источник
4
Или - как вы, вероятно, не знали - вместо ´ \ mv ` mv. Этот менее известный «трюк» приведет к тому, что команда с добавленной обратной косой чертой будет игнорировать любые определения псевдонимов.
синтаксическая ошибка
Конечно, если вы действительно говорите find ... -exec mv ..., то вам нужно создать ~/bin/mv(или какой-то другой соответствующий каталог) и сделать это /bin/mv -i "$@"- потому find ... -execчто не смотрит на псевдонимы.
G-Man говорит: «Восстановите Монику»
В этом случае я бы предпочел env mv. Меньше печатать. :) Поскольку моя локальная раскладка клавиатуры требует нажатия клавиши SHIFT для прямой косой черты, я всегда предпочел бы версии без косой черты (если применимо).
синтаксическая ошибка
1
@syntaxerror: Кстати, когда вы отвечаете на комментарий (в новом комментарии), обычно упоминается имя автора, которому предшествует «@», как в «@ G-Man». Таким образом я получаю уведомление. (Я смог ответить на ваш последний комментарий своевременно, потому что получил уведомление от комментария Дженни Д.). Вы можете сокращать или использовать полное имя (без пробелов), например, «@ StéphaneChazelas». Автор сообщения автоматически уведомляется о комментариях к этому сообщению. См. Разделы Ответы в комментариях на этой странице справки .
G-Man говорит «Восстановить Монику»
1
Извините, я был без Интернета в течение дня. @ G-Man Я согласен, что наличие личной версии mvв каком-то месте в начале $PATHбыло бы более чистым решением. С другой стороны, mvв интерактивной оболочке я, как правило, небрежно отношусь (потому что это происходит быстро). В тот момент я сочиняю что - то более сложное, как findили forцикл, или даже сценарий оболочки, я , как правило, выполнить некоторые сухие пробеги ( с помощью echo) , чтобы гарантировать , что я не нарушаю что - то. В этих случаях мне не нужно держать руку mv, потому что я уже вкладываю в нее некоторые мысли.
айекат
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более эффективно
Дженни Д
1
@Jenny: Если бы ваш find . -type d -exec mv {}/*9?.mp3 target \;пример работал, все равно был бы риск, что mvкоманда будет выглядеть mv file targetдля каждого каталога, который содержит только один *9?.mp3файл; поэтому все такие файлы (кроме последнего) будут потеряны.
G-Man говорит: «Восстановите Монику»
4
@syntaxerror: Я приветствую ваши усилия по раскрытию существенной части вашей проблемы, а не всего сценария с 42 000 строк, в котором она возникает. Но даже если вы хотите что-то сделать со всеми *.mp3файлами в дереве каталогов, вы можете, shopt -s globstarа затем запустить свою команду **/*.mp3- the **будет действовать как a find.
G-Man говорит: «Восстановите Монику»
1

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

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

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

  • Поместите содержимое файла в одну строку: ggVGJ
  • Prepend: Imv [esc]
  • Append: Asomedir/ [esc]
  • Сохраните файл. Прочитайте это снова. Вдохни.
  • Выполнить source tmpв командной строке.

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

Другими словами: я слишком труслив, чтобы использовать -exec.

Том Рис
источник
1
Вы пропустили этот :%s/.*/"&"/шаг - потому что в этом случае вы знаете, что каждое имя файла содержит хотя бы один пробел.
G-Man говорит: «Восстановите Монику»
1
Это будет кусать вас, если имена файлов содержат пробелы или другие специальные символы. Вы должны правильно процитировать их. Просмотр списка команд вряд ли может обнаружить ошибки. Существуют гораздо лучшие способы просмотра команд перед их выполнением, например запуск echo mvвместо mv, а затем удаление, echoесли вы счастливы.
Жиль "ТАК ... перестать быть злым"
Обнаружение ошибки, такой как имена файлов с пробелами, - это как раз то, с чем может помочь эта техника :-)
Том Рис
0

Другой вариант:

-n, --no-clobber не перезаписывать существующий файл

это то же самое, что -i, но оно не спросит, оно потерпит неудачу.

Хорхе Нерин
источник