为了复制除一个文件之外的所有文件:我通常使用表达式!(noThisFile)
(可通过shopt -s extglob
)。
在当前情况下,我想避免的是.git
目录。令人惊讶的是我尝试过:
cp -r !(.git) my-target-dir
../
但它也完全复制了目录的内容
事实上,当我
echo !(.git)
输出开始于:
. .. myDir myDir2 myFile myFile2
我不记得使用时复制时遇到过这样的问题当我检查文件名时,输出中!(notthisfile)
没有.
..
!(.avoidingDir)
对于我的系统来说,还应该同时返回.
和,这是否正确..
?- 如果是正确的,我应该怎样做才能避免这个问题?
答案1
这实际上有点有趣,因为至少 Bash 4.4 似乎也使用这种模式扩展到点文件,即使dotglob
没有生效。也许模式中的前导.
足以将它们带入,即使它位于否定之内。
如果正确与否,您必须询问 Bash 开发人员。它可能不应该这样做,因为在 Bash 5.0 中它不这样做。 (但如果dotglob
设置了,您仍然可以获得所有点文件,包括.
和..
。)
要获取除.git
, .
and之外的所有内容..
,您可以扩展模式以显式忽略.
and ..
,即!(.git|.|..)
,或使用GLOBIGNORE
隐藏.
and ..
:
$ mkdir .git .dot dir
$ echo !(.git|.|..)
dir .dot
$ GLOBIGNORE=.:..
$ echo !(.git)
dir .dot
(仅设置GLOBIGNORE
为任何非空值都会忽略.
和..
,但也会使 dotglob
.)
或者,如果您不想看到任何点文件,请确保dotglob
已禁用,然后只需使用*
,无需显式排除.git
:
$ unset GLOBIGNORE
$ shopt -u dotglob
$ echo *
dir
Zsh 也不会拉入.
and ..
,即使使用globdots
set,无论是使用 ksh 风格的!(.git)
还是使用 Zsh 自己的^.git
or *~.git
。
答案2
答案是:视情况而定。
如果 GLOBIGNORE 未设置,则 glob(任何 glob)都将匹配点文件和bash 选项 dotglob 已设置:
$ mkdir test; cd test; touch .git .one .two file myfile; \
mkdir .dir .new dir here
test $ ls -a
. .. .dir dir here .new file .git myfile .one .two
test $ unset GLOBIGNORE; shopt -s dotglob; echo *
.dir dir file .git here myfile .new .one .two
test $ unset GLOBIGNORE; shopt -u dotglob; echo *
dir file here myfile
test $ unset GLOBIGNORE; shopt -u dotglob; echo .*
. .. .dir .git .new .one .two
因此,如果未设置 dotglob,则点文件将被忽略。.*
例如,除非明确包含上述内容。
请注意,即使设置了,.
也必须显式匹配。..
dotglob
关于!(.git)
但是,是的,“!(.git)”(与任何带有起始点的东西一样)会触发“.”和“..”以及所有点文件的匹配。shopt -u dotglob; echo !(.a); shopt -s dotglob; echo !(.a)
dir file here myfile
. .. .dir dir file .git here myfile .new .one .two
您可以通过设置 GLOBIGNORE 来避免包含.
和。..
请记住,设置GLOBIGNORE
也会设置dotglob
,取消设置GLOBIGNORE
也会取消设置dotglob
。
test $ shopt -u dotglob; GLOBIGNORE="."; shopt -p dotglob; echo !(.a)
shopt -s dotglob
.dir dir file .git here myfile .new .one .two
test $ shopt -s dotglob; unset GLOBIGNORE; shopt -p dotglob; echo !(.a)
shopt -u dotglob
dir file here myfile
因此,作为解决方法,请将 GLOBIGNORE 设置为以避免和.:..
的扩展。.
..