mv ./* ../somedirectory
最近,当我做了类似的事情并发现类似的文件.gitignore
没有被移动时,我感到很惊讶。
我的大部分工作都是在 OS X 上的 zsh 中完成的,而这个惊喜让我在 CentOS 上的 bash 中完成。我在 OS X 上尝试了 bash 并发现了相同的行为:*
与点文件不匹配。这对我来说似乎非常不可取,但显然这是 bash 的默认设置。 (据我所知,这也可能是 zsh 默认值,但我可能几年前在我的 .zshrc 中更改了它,并且忘记了它的工作方式有所不同。)
如何配置 bash 使其按我的预期运行: for * 匹配所有文件,而不忽略点文件。
如果这根本不清楚,这里是如何重现它
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
答案1
重击
正如您已经注意到的那样,bash 不会匹配.
名称开头的 a 或斜杠。要更改有关点的匹配,您必须设置选项dotglob
-男人狂欢:
dotglob 如果设置,bash 包含以“.”开头的文件名在 路径名扩展的结果。
要使用 bash 使用启用/设置它shopt
,例如:
shopt -s dotglob
对于 zsh,您也可以使用该dotglob
选项,但您必须使用setopt
它来启用它,例如:
setopt dotglob
答案2
*
是一个由 shell 扩展的 glob。默认情况下,shell 不包含名称以 a 开头的文件.
(称为隐藏文件或点文件),除非按.
字面意思输入前导。
*
or [.]*
or or or?*
不包含点文件。*.*
dir/*
.*
或dir/.*
将。
所以你可以这样做:
mv -- * .* /dest/
然而,一些 shell 包括bash
(但不是zsh
,mksh
也不是)具有这样的错误功能,即包含和特殊目录条目fish
的扩展,这是您在这里不想要的(并且通常不希望包含 glob,这就是为什么我称其为错误功能)。.*
.
..
因此,您会发现有时人们使用(在类似 Bourne 的 shell 中):
mv -- * .[!.]* ..?* /dest/
这是三个 glob,第一个匹配非隐藏文件,第二个文件名以 开头,.
后跟一个字符以外的字符.
,第三个文件名以 开头,..
后跟至少一个字符。
然而,一些现代 shell 有更好的方法来解决这个问题
桀骜
通过zsh
,您可以使用(D)
glob 限定符来指定 glob 应包含点文件:
mv -- *(D) /dest/
zsh
还修复了 Bourne shell 的其他错误功能,即如果模式不匹配,mv
则不会运行该命令。
如上所述,它也永远不会包含.
或包含..
在其全局中,所以
mv -- * .* /dest/
会安全的。但是,如果没有文件匹配*
或没有文件匹配,.*
命令将被中止,因此最好使用:
mv -- (*|.*) /dest/
与其他一些 shell 一样,您还可以强制所有 glob 包含点文件(例如,如果您发现自己更频繁地希望包含点文件):
setopt dotglob
或者:
set -o dotglob
之后,如果你想要一个特定的 glob不是要包含点文件,您可以编写:
echo *(^D)
或者:
echo [^.]*
重击
不幸的bash
是没有全局限定符。因此,您只能在全局范围内启用点文件包含。在 中bash
,语法为:
shopt -s dotglob
(并用于[^.]*
没有隐藏文件的 glob)。
对于dotglob
,bash
不包括.
也不包含..
在像 之类的全局变量中*
,但对于像 之类的全局变量仍然如此.*
。
如果您将GLOBIGNORE
变量设置为非空值,它会自动启用该dotglob
选项并从glob中排除.
and ,但不从or中排除(!),因此这种保护措施几乎毫无用处。你可以这样做,但它会破坏像or or 这样的全局变量。..
.*
dir/.*
.*/file
GLOBIGNORE='*/.:*/..:./*:../*:*/./*:*/../*'
*/.
./*
../*
更好的解决方法是使用[.]*
or dir/[.]*
or [.]*/file
(dotglob
启用)来扩展除.
和之外的点文件..
。
鱼
fish
glob 不包括.
Nor ..
。当没有匹配项时,根据版本的不同,它将像zsh
(or bash -o failglob
) 或一样工作bash -o nullglob
。
mv -- * .* /dest/
如果同时存在隐藏和非隐藏文件,则可以使用。否则,YMMV 和某些版本,mv -- /dest
如果根本没有文件,它可能会调用。
克什93
两者都没有全局限定符ksh93
。您可以使用以下命令将点文件包含在 glob 中:
FIGNORE='@(.|..)'
与bash
's相反,这样做是正确的,并且还解决了包含和GLOBIGNORE
的问题。.*
.
..
亚什
yash
有一个dot-glob
选项 ( set -o dot-glob
),但与 相反bash
,全局扩展(甚至是*
)包含在内.
,..
因此它非常无用。
tcsh
set globdot
与 in 类似bash
,即包含除和*
之外的点文件,但仍包含和(并且您可以使用它来展开除和之外的隐藏文件)。.
..
.*
.
..
[.]*
.
..
答案3
我对此进行了测试,它解决了这个问题:
shopt -s dotglob
输出:
~/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....
答案4
非常感兴趣 GLOBIGNORE=/+/ @user79743 的这个设置
根据我的经验取消设置点团是生意不好几乎所有的命令(cp、mv 等)但同样如此环境nullglob(尤其是需要转义的正则表达式!)。
不过,如果您确实需要在程序开头设置它们,但会干扰调用 cp、mv 等命令或使用正则表达式的特定部分,只需执行以下操作:
# set dotglob, unset nullglob AFTER this
is_nullglob=$( shopt -s | egrep -i '.*nullglob' )
is_dotglob=$( shopt -s | egrep -i '.*dotglob' )
[[ $is_nullglob ]] && shopt -u nullglob
[[ ! $is_dotglob ]] && shopt -s dotglob
# ... call commands ...
# .....................
# reset dotglob, nullglob to their previous values
[[ $is_nullglob ]] && shopt -s nullglob
[[ ! $is_dotglob ]] && shopt -u dotglob