带有glob模式的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)

我的目录充满了隐藏的文件夹和文件。发生了什么,解决方案是什么?


dotglobglobdotszsh转换为bash的无效选项名称。

Answers:


19

免责声明:该答案专门针对Bash,但其中大部分适用于有关glob模式的问题!

星号(*)是通配符。有一定的字符集可以代替,而第一个字符是点(.)并不是其中一个。这是一种特殊情况,仅因为Unix文件系统如何工作,以点开头的文件被认为是“隐藏的”。这意味着,工具等cpls等,将“看”不到它们,除非明确告知这样做。

例子

首先,让我们创建一些样本数据。

$ 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/. .

1
您可能要提及的使用shopt -s dotglobecho *然后给出:.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
Drav Sloan 2013年

@DravSloan-感谢您的建议。添加了。
slm

cp -r foo .通常可能无法正常工作,因为您可能cp会拒绝复制foo自身cp -R foo/. .。(请注意,这cp -R是标准的)。
斯特凡Chazelas

1
另请注意,(非常明智地)在的扩展zsh中不包含.和。在中,如果模式不匹配,该命令将中止(再次明智地退出),因此在一般情况下,如果没有隐藏文件或没有非隐藏文件,该命令将失败。...*zshcp foo/{,.}* .
斯特凡Chazelas

7
此答案仅适用于bash。询问者使用的是zsh,答案很简单并且shopt不存在。
吉尔(Gilles)“所以,别再邪恶了”

31

使用zsh,典型的方法是使用D 全局限定符(包括[D] ot文件):

cp foo/*(D) .

请注意,无论是否使用D,zsh glob都不会包含...(如您所愿)。


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

StéphaneChazelas的zsh 答案对于其中包含glob的单个表达式是正确的。但是,如果要默认为所有表达式设置它,则可以使用

setopt GLOB_DOTS

把它放在你的~/.zshrc永久。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.