Вопрос или проблема
Я перемещаю свой домашний каталог со старой системы на новую, и созданный мной архив tarball содержит все, включая скрытые файлы, такие как .bashrc. Однако, когда я перемещаю содержимое распакованного архива tarball (которое находится в /tmp) в свой новый домашний каталог, скрытые файлы не копируются (mv /tmp/home/rcook/* /home/rcook/
). Как мне заставить mv перемещать их?
На самом деле, я думаю, проблема не в mv, а в глоббировании bash. Если я делаю так:
mkdir a
mkdir b
touch a/.foo
touch a/bar
mv a/* b/
ls -a a/ b/
Я вижу это:
a/:
. .. .foo
b/:
. .. bar
a/.foo
не переместился. Так как же заставить * находить скрытые файлы?
Да, я мог бы распаковать tarball напрямую в свой домашний каталог, но tarball распаковывается в home/rcook/...
, и я хочу быть уверенным, что перезаписываю новый .bashrc
и т.д. старыми, кастомизированными версиями, и знание, как находить и перемещать скрытые файлы, является полезным навыком. Предложения?
Некоторые ответы предполагают сделать что-то вроде mv src/.* dest/
. Однако я попробовал это в своих тестовых каталогах и получил ошибки. Начав с:
rcook$ ls -a a/ b/
a/:
. .. bar .foo
b/:
. ..
rcook$ mv a/.* b/
mv: не удается переместить 'a/.' в 'b/.': Устройство или ресурс занят
mv: не удается удалить 'a/..': Это директория
rcook$ ls -a a/ b/
a/:
. .. bar
b/:
. .. .foo
Что я делаю неправильно?
Вы можете сделать следующее:
shopt -s dotglob
mv /tmp/home/rcook/* /home/rcook/
Вы можете поместить
shopt -s dotglob
в ваш ~/.bashrc
, если хотите, чтобы это стало параметром по умолчанию.
См. http://mywiki.wooledge.org/glob
Другой подход для копирования точечных файлов:
mv /tmp/home/rcook/.[!.]* /home/rcook/
Не используйте паттерн ..*
, так как он совпадает с ..
(указатель на родительскую директорию). Если есть файлы, начинающиеся с двух точек (..something
), также используйте паттерн ..?*
.
В ваших дополнениях возникли ошибки, но код все равно сработал. Единственное, что нужно добавить, это то, что вы указали перемещать только точечные файлы. Попробуйте:
mv src/* src/.* dst/
Вы все равно получите ошибки для записей . и .., что нормально. Но перемещение должно быть успешным.
~/scratch [andrew] $ mv from/* from/.* to/
mv: не удается переместить ‘from/.’ в ‘to/.’: Устройство или ресурс занят
mv: не удается удалить ‘from/..’: Это директория
~/scratch [andrew] $ ls -a from/ to/
from/:
. ..
to/:
. .. test .test
Если вы ls -l
в каталоге, вы увидите .
и ..
среди перечисленных файлов. Поэтому, я думаю, что mv .* /dest
принимает во внимание эти указатели. Попробуйте:
mv /tmp/home/rcook/{*,.[^.]*,..?*} /home/rcook/
это проигнорирует эти указатели на текущие и родительские директории.
Вы получите ошибку, если какой-либо из трех паттернов *
, [^.]*
или ..?*
не совпадет ни с одним файлом, поэтому включайте только те, которые совпадают.
Два возможных решения, которые я могу предложить. Первое – использовать cp вместо этого с его рекурсивной опцией, скопировав текущий каталог в пункт назначения.
cp -Rp . /desired/directory
затем удалить исходные файлы в текущем каталоге
Альтернативно, если вы знаете, что файлы имеют разумные названия (без пробелов, подстановочных знаков, непечатных символов), вы можете сделать что-то вроде этого
mv $(ls -A) /desired/directory
Я знаю, что это старо, но, один простой способ сделать это:
mv a/{.*,*} b/
Объяснение
Это называется расширением фигурных скобок. В этом случае оболочка расширяет путь, который вы указали, конкатенируя строку, данную перед фигурными скобками (в этом случае a/
), с каждой вариацией, указанной в списке, окруженном фигурными скобками.
Список вариаций составлен из значений, разделенных запятыми и снова окруженных фигурными скобками. Таким образом, в этом случае у нас есть .*
и *
как элементы, так что список должен быть {.*,*}
.
mv a/{.*,*} b/
Выражение выше можно прочитать следующим образом: переместите все файлы, начинающиеся с точки (.*
) И все остальное (*
) в директории a/
в директорию b/
.
Больше советов
Это очень полезно и может быть использовано в различных сценариях. Например, представьте, что вам нужно создать 100 файлов с таким шаблоном именования: file1, file2, file3… file100. Вы можете легко добиться этого, сделав следующее
touch file{1..100}
В этом случае вы видите, что было задано диапазон. Вы можете сделать это, разделив первое и последнее значения двумя точками (..
).
Переходя на следующий уровень!
Я новичок в мире Unix и, даже зная, что это работает в bash
и zsh
(оболочки, которые я использовал до сих пор), я не могу гарантировать, что это будет работать в любой оболочке.
Вы можете узнать больше о расширениях и глоббировании в документации вашей оболочки (используйте: man bash
или man zshall
для bash и zsh соответственно).
Надеюсь, это поможет будущим читателям!
На самом деле нет такого понятия, как “скрытые” файлы в Linux. Файлы, начинающиеся с точки, просто по умолчанию скрыты из списка файлов.
Чтобы скопировать файлы, даже с подстановкой, вам нужно добавить к файлу префикс .
, такой как mv -u .* foo
, и затем .foo
появится как foo/.foo
при перемещении.
Опция -u переместит файлы только в том случае, если исходный файл новее или если его нет в пункте назначения. Или вы можете просто игнорировать ошибки о перемещении .
и ..
, так как это специальные файлы и их нельзя перемещать, но оболочка захватывает их в .*
.
Так у нас есть:
a
|-- .foo
`-- bar
и:
b
Я потратил огромное количество времени, чтобы найти лучшее решение, чем все ответы здесь.
Затем я потратил 30 секунд на эту команду:
$ mv --help
Затем я нашел свою любовь:
$ mv a/ b/ -T
Примечание: я даже не понимаю аргумент -T
. Он просто сделал то, что мне было нужно. Здесь сказано:
-T, –no-target-directory
рассматривайте DEST как обычный файл
В моем случае я просто пытался mv
одиночный скрытый файл и это было решением:
FILE=.myHiddenFile
mv "$FILE" dest/
Объяснение
Сначала я пытался:
mv .myHiddenFile dest/
Но все время выдавалась ошибка:
mv: cannot stat '.myHiddenFile': No such file or directory
Даже когда ls -al
показывал, что файл и dest/
существовали.
Причина, видимо, в том, что оболочка интерпретировала “.” в имени файла, поэтому, перемещая его в переменную, вы избегаете интерпретации. Вероятно, есть и другие способы решения этой проблемы, но этого было достаточно.
Альтернативный способ – использовать (GNU) find
:
find /tmp/home/rcook/ -mindepth 1 -maxdepth 1 -exec mv {} /home/rcook/ \;
Чтобы переместить все файлы и каталоги из текущей директории в ее
родительскую директорию, вы можете использовать
mv * ../
Примечание: Это не сработает, если вы хотите переместить скрытые файлы или каталоги,
Если вам нужно переместить скрытые файлы, используйте следующую команду.
mv * .[^.]* ../
Ответ или решение
При переносе файлов из временной директории в домашний каталог, важно учитывать, что команды и символы в Linux работают по определённым правилам, которые могут создавать неожиданные сложности. Например, обычное использование символа *
не учитывает скрытые файлы, начинающиеся с точки, такие как .bashrc
. Таким образом, при команде mv /tmp/home/rcook/* /home/rcook/
скрытые файлы не будут перенесены.
Чтобы переместить скрытые файлы, можно воспользоваться несколькими подходами:
1. Использование dotglob в bash:
При помощи команды shopt -s dotglob
включается возможность учитывать скрытые файлы в результатах разворачивания. После этого команда mv /tmp/home/rcook/* /home/rcook/
переместит в том числе и файлы с точкой в начале. Если вы хотите, чтобы эта опция всегда была включена, добавьте её в ваш ~/.bashrc
.
shopt -s dotglob
mv /tmp/home/rcook/* /home/rcook/
2. Использование альтернативных выражений для глобщения:
Можно также использовать расширенные выражения для перемещения файлов, чтобы они включали скрытые файлы, игнорируя ошибки связанных с разделами .
и ..
.
mv /tmp/home/rcook/{*,.[^.]*,..?*} /home/rcook/
Эта команда гарантирует, что все файлы включая скрытые, перенесутся корректно, избегая перемещения видимых и невидимых системных директорий .
и ..
.
3. Использование команды find
:
Команда find
может быть более гибким способом переноса файлов:
find /tmp/home/rcook/ -mindepth 1 -maxdepth 1 -exec mv {} /home/rcook/ \;
Эта команда перемещает все файлы и директории (включая скрытые) из директории /tmp/home/rcook/
в /home/rcook/
.
Каждый из этих методов предлагает надежное решение для задачи переноса всех файлов, включая скрытые, и может быть адаптирован в зависимости от конкретных требований и настроек системы. Убедитесь в правильности синтаксиса и соответствия ваших действий выбранному подходу, чтобы достичь нужного результата.