bash中globbing的设置是什么,控制*是否匹配点文件

ico*_*ast 12 bash wildcards

最近当我做了类似的事情mv ./* ../somedirectory 并发现文件.gitignore没有移动时,我感到很惊讶 。

我的大部分工作都是在 OS X 上的 zsh 中完成的,而这个惊喜让我在 CentOS 上的 bash 中感到惊讶。我在 OS X 上尝试了 bash 并发现了相同的行为:*与点文件不匹配。这对我来说似乎很不受欢迎,但显然这是 bash 的默认设置。(这可能也是我记得的所有 zsh 默认值,但我可能在几年前在我的 .zshrc 中更改了它并忘记了它的工作方式不同。)

如何将 bash 配置为按我预期的方式运行:用于 * 匹配所有文件,而不是忽略点文件。

如果这完全不清楚,这里是如何重现它

cd /tmp
mkdir {t,d}est
touch test/{.,}{1,2,3,4,5,6,7}
ls -hal test
mv test/* dest
ls -hal test     # notice dot files are still there
ls -hal dest     # notice only some files were mv'ed
Run Code Online (Sandbox Code Playgroud)

Ulr*_*gel 15

重击

正如您已经注意到的那样,bash.与名称开头的 a 或斜杠不匹配。要更改有关点的匹配,您必须设置dotglob选项 - man bash

dotglob 如果设置,bash 将包含以“.”开头的文件名 在
    路径名扩展的结果。

要使用 bash 启用/设置它shopt,例如:

shopt -s dotglob
Run Code Online (Sandbox Code Playgroud)


对于 zsh,您也可以使用该dotglob选项,但您必须使用setopt它来启用它,例如:

setopt dotglob
Run Code Online (Sandbox Code Playgroud)

  • 使用`zsh`,更好的选择是在每个glob 的基础上启用_dotglob_:`mv test/*(D) /dest` (2认同)

Sté*_*las 9

*是一个由 shell 展开的 glob。默认情况下,shell 不包含名称以 a 开头的文件.(称为隐藏文件或点文件),除非按.字面意思输入前导。

*[.]*?**.*dir/*将不包括点文件。

.*dir/.*将。

所以你可以这样做:

mv -- * .* /dest/
Run Code Online (Sandbox Code Playgroud)

但是,包括bash(但不是zshmksh也不是fish)的某些 shell具有错误功能,即扩展.*包含...特殊目录条目,您在这里不想要(并且通常从不希望包含 glob,这就是我将其称为错误功能的原因)。

出于这个原因,您会发现有时人们使用(在类似 Bourne 的 shell 中):

mv -- * .[!.]* ..?* /dest/
Run Code Online (Sandbox Code Playgroud)

这是三个 glob,第一个匹配非隐藏文件,第二个文件名以 开头,.后跟一个字符以外的字符.,第三个文件名以 开头,..后跟至少一个字符。

然而,一些现代 shell 有更好的方法来解决这个问题

zsh

使用zsh,您可以使用(D)glob 限定符指定 glob 应包含点文件:

mv -- *(D) /dest/
Run Code Online (Sandbox Code Playgroud)

zsh还修复了 Bourne shell 的其他错误功能,因为如果模式不匹配,mv则不会运行该命令。

如上所述,它也永远不会包括.也不..在其球体中,所以

mv -- * .* /dest/
Run Code Online (Sandbox Code Playgroud)

将是安全的。但是,如果没有文件匹配*或没有文件匹配.*该命令将被中止,因此最好使用:

mv -- (*|.*) /dest/
Run Code Online (Sandbox Code Playgroud)

像在其他一些 shell 中一样,您也可以强制所有 glob 包含点文件(例如,如果您发现自己想要更频繁地包含点文件):

setopt dotglob
Run Code Online (Sandbox Code Playgroud)

或者:

set -o dotglob
Run Code Online (Sandbox Code Playgroud)

之后,如果您希望特定的 glob包含点文件,您可以编写它:

echo *(^D)
Run Code Online (Sandbox Code Playgroud)

或者:

echo [^.]*
Run Code Online (Sandbox Code Playgroud)

重击

不幸的bash是没有全局限定符。因此,您只能在全局范围内启用 dotfile 包含。在 中bash,语法是:

shopt -s dotglob
Run Code Online (Sandbox Code Playgroud)

(并[^.]*用于没有隐藏文件的 globs)。

With dotglob,bash既不包含.也不包含..在 globs 中*,但仍然适用于.*.

如果您将GLOBIGNORE变量设置为非空值,则它会自动启用该dotglob选项....*globs 中排除and from globs 而不是 from dir/.*or .*/fileones (!),因此保护措施非常无用。你可以这样做,GLOBIGNORE='*/.:*/..:./*:../*:*/./*:*/../*'但它会破坏像*/.or./*或 or 之类的球体../*

更好的解决方法是使用[.]*ordir/[.]*[.]*/filedotglob启用)扩展除.and之外的点文件..

fishglobs 不包括.也不包括... 当没有匹配项时,取决于版本,它将像zsh(或bash -o failglob) 或bash -o nullglob.

mv -- * .* /dest/
Run Code Online (Sandbox Code Playgroud)

如果同时存在隐藏文件和非隐藏文件,则可行。否则,YMMV 和某些版本,mv -- /dest如果根本没有文件,它可能会调用。

ksh93

ksh93两者都没有 glob 限定符。您可以将 dotfiles 包含在 globs 中:

FIGNORE='@(.|..)'
Run Code Online (Sandbox Code Playgroud)

bash's相反GLOBIGNORE,这是正确完成的,并且还解决了.*包含.和的问题..

亚什

yash有一个dot-glob选项(set -o dot-glob),但相反bash,水珠扩展(甚至*)包括...因此它的好看不中用。

tcsh

set globdot
Run Code Online (Sandbox Code Playgroud)

像 in 一样工作bash,即*包含点文件,除了.and...*仍然包含...(并且您可以[.]*用来扩展除.and之外的隐藏文件..)。


Jod*_*e C 7

我对此进行了测试,它解决了问题:

shopt -s dotglob
Run Code Online (Sandbox Code Playgroud)

输出:

~/stackexchangeanswers/40662$ ls -hal dest
total 8.0K
drwxr-xr-x 2 jodiec jodiec 4.0K 2012-06-12 22:15 .
drwxr-xr-x 4 jodiec jodiec 4.0K 2012-06-12 22:15 ..
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 3
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .3
...snipped....
Run Code Online (Sandbox Code Playgroud)

  • 我们都在同一个团队。没关系。 (3认同)