Случайное перемещение файлов в несуществующий каталог стирает файлы?

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

Система вернула сообщение, что каталог не существует, но мои файлы из исходного каталога были удалены.

Это ошибка? Следует ли перемещать файлы в несуществующее место, чтобы удалить перемещаемые файлы? (Это на Ubuntu 18.04.2 LTS.)


Особенности были:

  1. Создан test.txt файл.
  2. Переместили файл в /ben с помощью sudo.
  3. Файл исчез. /ben не существует.

Команды и выходные данные были:

ben.b@c-w46:~/Desktop/test-folder$ sudo mv test.txt /ben
ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory
7
задан 26 July 2019 в 02:11

2 ответа

В команде Вы на самом деле работали, Вы ничего не потеряли! Это успешно выполнилось при переименовании test.txt кому: /ben. Принятие test.txt был регулярный файл, новое - также /ben (они - тот же файл, в конце концов).

Причина Вы видите bash: cd: /ben: Not a directory то, что это говорит относительно олова: /ben не каталог. Можно все еще получить доступ к файлу.

Если Вы хотите избежать такой ошибки и силы mv чтобы перестать работать, если место назначения не является каталогом, запишите запаздывание / на нем или использование -t dir. Например, любой из них предотвратил бы (очень незначительный!) проблема Вы испытали (с sudo по мере необходимости):

mv test.txt /ben/  # no action, unless `/ben` is an existing directory
mv -t /ben test.txt  # same deal, -t doesn't accept regular-file operands
mv -t /ben/ test.txt  # you can even do both if you want

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


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

Например, предположите, что я имею:

ek@Apok:~/tmp$ ls -F
dest/       file02.txt  file04.txt  file06.txt  file08.txt  file10.txt
file01.txt  file03.txt  file05.txt  file07.txt  file09.txt

Перемещать все те файлы в dest, Я должен передать все их имена к mv, в команде как mv file*.txt dest/ или mv file*.txt dest. В любом случае - то есть, пишу ли я целевое имя каталога с запаздывающей наклонной чертой - это делает правильную вещь. И в любом случае, если я пишу целевое имя каталога c орфографическими ошибками (говорят, путем записи dst вместо этого), я получаю ошибку mv: target 'dst' is not a directory и никакие данные не потеряны.

Однако предположите, что я должен был написать c орфографическими ошибками dst, опустите запаздывание /, и выполненный несколько mv команды. Это было бы плохо, потому что когда место назначения mv регулярный файл, mv замены это!

ek@Apok:~/tmp$ mv file01.txt dst  # bad if dst exists but isn't a directory
ek@Apok:~/tmp$ mv file02.txt dst  # bad, I just lost the old file01.txt!

Поэтому многие люди предпочитают всегда писать целевые каталоги с запаздыванием / в mv:

ek@Apok:~/tmp$ mv file03.txt dst/
mv: failed to access 'dst/': Not a directory

Можно использовать mv -i спросить Вас перед перезаписью, или mv -n к тихо не перезаписывают. Иначе, mv только спросите Вас прежде, чем перезаписать, если место назначения является файлом только для чтения. Одна причина рассмотреть это состоит в том, что это покрывает другие случаи, как mv file01.txt dest/ где Вы не поняли dest/file01.txt существовавший и не хотел перезаписывать его.

Можно также использовать -t dest вместо записи dest в конце команды, например, mv -t dest file*.txt. Это отказывается работать если dest регулярный файл, независимо от того, пишете ли Вы запаздывание /.


Используя автоматизированный механизм для выполнения нескольких таких команд может серьезно усугубить проблему. Например, как записано команда for f in file*.txt; do mv "$f" dest/; done является напрасно сложным, но безопасным, потому что, если я случайно указал файл dst вместо каталога dest (но сохраненный наклонной чертой!), это дало бы мне один mv: failed to access 'dst/': Not a directory ошибка на файл. Однако, если я опустил запаздывание /, затем это переименовало бы каждый файл к dst, замена предыдущего dst, и только последний файл остался бы.

Подобные плохие результаты могут быть достигнуты с find, включая в ситуациях, где может быть разумно использовать find (но по-другому, и все еще с дополнительной осторожностью). Например, предположите, что я хотел переместить все файлы, соответствующие шарику file*.txt во всем дереве каталогов (кроме dest самостоятельно) в каталог dest. Я мог бы сначала думать для использования этого:

find . -path ./dest -prune -o -name 'file*.txt' -exec mv {} dest/ \;  # bad, don't use

Поскольку я включал запаздывание /, запись dest/ вместо dest, это не перезаписало бы названный файл dst даже если я записал dst вместо dest. Но это имеет связанную проблему, что это перезапишет файлы, которые это уже скопировало, если файлы в различных частях дерева каталогов имеют то же имя. Например, если существует a/file01.txt и a b/file01.txt, каждый перезапишет другой. Чтобы избежать, чтобы также было лучше использовать что-то вроде этого:

find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} \;  # okay

Другое преимущество -t dir это, потому что это позволяет Вам указать целевой каталог перед перемещаемыми объектами, это совместимо с + форма -exec, куда несколько объектов передаются команде, таким образом, выполняя меньше команд (часто всего одна):

find -path ./dest -prune -o -name 'file*.txt' -exec mv -it dest/ {} +  # good

В обоих случаях (они - то же за исключением \; по сравнению с. +) Я также передал -i опция запросить перед каждой операцией, которая перезаписала бы файл. Если Вы просто хотите тихо пропустить их, записать n вместо i. Если Вы хотите протестировать Ваш find команды сначала, можно записать echo после -exec но перед остальной частью команды для печати, что было бы выполнено. Например:

ek@Apok:~/tmp$ find -path ./dest -prune -o -name 'file*.txt' -exec echo mv -it dest/ {} +
mv -it dest/ ./file02.txt ./file06.txt ./file10.txt ./file09.txt ./file01.txt ./file04.txt ./file05.txt ./file07.txt ./file03.txt ./file08.txt

(Конечно, это находится в исходном каталоге, который я показал, где все файлы к перемещенному находятся в том же месте, и таким образом где find излишество, и самая сложная разумная команда для использования mv -it dest/ file*.txt.)

12
ответ дан 23 November 2019 в 06:11

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

Несколько вещей:

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

Если СУЩЕСТВУЕТ сделанное перемещение...

  • Посмотрите info coreutils 'mv invocation' (интерактивная версия https://www.gnu.org/software/coreutils/manual/html_node/mv-invocation.html#mv-invocation) для того, как mv работает и более конкретный эта часть:

    Это сначала использует часть того же кода, это используется ‘CP-a’ для копирования требуемых каталогов и файлов, затем (принимающий копию, за которой следуют), это удаляет оригиналы. Если копия перестала работать, то часть, которая была скопирована в целевой раздел, удалена. Если бы необходимо было скопировать три каталога от одного раздела до другого и копии первого каталога, за которым следуют, но второе не сделало, то первое оставили бы на целевом разделе и втором, и третье оставили бы на исходном разделе.

  • Таким образом, перемещение состоит из 2 частей:

    1. a cp -a
    2. a mv

    Часть удаления перемещения сделана ПОСЛЕ ТОГО, КАК существует подтверждение, копия была сделана правильно.

  • если Ваш mv состоит из нескольких файлов, копия и перемещение сделаны промежуточные. Так a

    mv a b c d e f /dir/
    

    сделает a

    cp a /dir/
    rm a
    ...
    cp f /dir/
    rm f
    

    таким образом, когда существует проблема промежуточный a и f, это закончит перемещение a и туда, где проблема появилась. Это также относится к использованию подстановочных знаков.


Относительно редактирования

sudo mv test.txt /ben

Это перемещает test.txt в / и переименовывает его к ben. И

ben.b@c-w46:~/Desktop/test-folder$ cd /ben
bash: cd: /ben: Not a directory

правильно ошибки. Сделайте a

ls -l /ben

и это покажет файл.

То, что всегда необходимо делать, добавляют / если Вы хотите переместить файл в каталог.

sudo mv test.txt /ben/

был бы ошибка как/ben/не делает существует.

8
ответ дан 23 November 2019 в 06:11

Другие вопросы по тегам:

Похожие вопросы: