cp скрытые файлы с шаблонами глобуса

13

Ситуация:

$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat foo/*’: No such file or directory)

У меня есть каталог, полный скрытых папок и файлов. Что происходит и каково решение?

градиент
источник
dotglobтранслируются globdotsпо Zsh , которая недопустимое имя опции для Баша .

Ответы:

19

Отказ от ответственности: Этот ответ касается конкретно Bash, но большая часть его относится к вопросу о шаблонах глобуса!

Символ звезды ( *) является подстановочным знаком. Есть определенный набор символов, который он заменит, и первый символ, являющийся точкой ( .), не является одним из них. Это особый случай только из-за того, как работают файловые системы Unix, файлы, начинающиеся с точки, считаются «скрытыми». Это означает, что такие инструменты, как cp,ls и т. Д. Не будут «видеть» их, если явно не указано иное.

Примеры

Сначала давайте создадим несколько примеров данных.

$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}

Итак, теперь у нас есть следующее:

$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3

Теперь давайте поиграем в некоторые игры. Вы можете использовать команду, echoчтобы перечислить, какой будет подстановочный знак ( *) для данной команды, например:

$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3


$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2

$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .dotdir*
.dotdir1 .dotdir2

Изменение поведения?

Вы можете использовать команду, shopt -s dotglobчтобы изменить поведение *так, чтобы в дополнение к файлам, как regfile1это также будет соответствовать.dotfile1 .

выдержка из bashсправочной страницы

dotglob If set, bash includes filenames beginning with a `.' in the results 
        of pathname expansion.

Пример:

$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

Вы можете восстановить это поведение с помощью этой команды:

$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3

Ваша ситуация?

Для вас вы говорите, cpчто хотите скопировать все файлы, которые соответствуют шаблону *, и нет никаких файлов.

$ cp foo/.* .

Или вы можете сделать это, если хотите все в fooпапке:

$ cp foo .

Или вы можете быть явным:

$ cp foot/.* foo/* .

Более компактная форма с использованием расширения скобки в bash:

$ cp foo/{.,}* .

В любое время вы можете использовать echoтрюк, чтобы увидеть, какие у вас предложены шаблоны файлов (это причудливый термин для обозначения того, что является звездой).

$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3

Кстати, если вы собираетесь скопировать каталог файлов + другие каталоги, вы, как правило, хотите сделать это рекурсивно, это -Rпереключение на cp:

$ cp -R foo/. .
SLM
источник
1
Вы можете упомянуть использование shopt -s dotglob, а echo *затем дает:.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
Драв Слоан
@DravSloan - спасибо за предложение. Добавил это.
СЛМ
cp -r foo .как правило, не будет работать, так cpкак откажется копировать fooсам, вы, вероятно, подразумевали cp -R foo/. .. (обратите внимание, что cp -Rэто стандартный).
Стефан Шазелас
1
Также отметим, что (вполне разумно) zshне включает .и ..в расширение .*. В zsh, если шаблон не соответствует, то команда прерывается (вполне здраво снова), так что в общем случае, cp foo/{,.}* .не получится, если нет не скрыто или нет не-скрытых файлов.
Стефан Шазелас
7
Этот ответ относится только к bash. Аскер использует zsh, где ответ намного проще и shoptне существует.
Жиль "ТАК - перестань быть злым"
29

С zshтипичным способом является использование D спецификатора glob (для включения [D] ot файлов):

cp foo/*(D) .

Обратите внимание, что с или без D, zsh-глобусы никогда не включают .ни ..(как вы ожидаете).

Стефан Шазелас
источник
4

Оболочка обрабатывает эти файлы как скрытые, когда разрешает *символ, поэтому cpне получает ни одно из этих имен файлов в качестве аргументов.

Вы можете скопировать их, явно указав cp foo/.* .

переигровка
источник
1

Если вы хотите скопировать все файлы и каталоги из одного места в другое, вы можете использовать стандартную rsyncкоманду. В приведенном выше примере:

mkdir foo && touch foo/.test
rsync -a foo/ .

будет рекурсивно копировать все содержимое foo, включая скрытые файлы и скрытые каталоги, в текущий каталог. Конечный слеш в конце foo/важен для rsync; при этом fooкопируется только содержимое , без него также копируется rsync foo. Например:-

mkdir src && mkdir dest && touch src/.test
rsync -a src  dest    // copies 'src' contents to 'dest/src'
rsync -a src/ dest    // copies 'src' contents to 'dest' 

Есть много других доступных опций настройки rsync, включая копирование между компьютерами.

Роб Сварбрик
источник
1

Zsh- ответ Стефана Шазеласа верен для одного выражения с глобусом в нем. Однако, если вы хотите установить его для всех выражений по умолчанию, вы можете использовать

setopt GLOB_DOTS

Положите его в свой, ~/.zshrcчтобы сделать его постоянным.

Sparhawk
источник