如何将一个目录中的所有文件(包括隐藏文件)移动到另一个目录?
例如,如果我有一个文件夹“Foo”,其中包含文件“.hidden”和“notHidden”,如何将这两个文件移动到名为“Bar”的目录?以下内容不起作用,因为“.hidden”文件保留在“Foo”中。
mv Foo/* Bar/
自己尝试一下。
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
答案1
先快速回答;有关 bash、ksh93 和 zsh 的更深入讨论和文档链接,请参阅下文。
兹什
mv Foo/*(DN) Bar/
或者
setopt glob_dots null_glob
mv Foo/* Bar/
选项名称中的大小写和下划线将被忽略。set -o
也可以像在类似 Korn/POSIX 的 shell 中一样使用,并且dotglob
还支持 (DotGlob、DOT_GLOB...) 以与 GNU shell (bash) 兼容。
重击
shopt -s dotglob nullglob
mv Foo/* Bar/
肯什93
如果您知道该目录不为空:
FIGNORE='.?(.)'
mv Foo/* Bar/
鱼
如果您知道该目录不为空:
mv Foo/{.,}* Bar/
标准 (POSIX) sh
for x in Foo/* Foo/.[!.]* Foo/..?*; do
if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done
如果您愿意让mv
命令返回错误状态,即使它成功了,它也会简单得多:
mv Foo/* Foo/.[!.]* Foo/..?* Bar/
GNU find 和 GNU mv
find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +
标准查找
find Foo/. ! -name . -prune -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} +
以下是有关控制点文件在 bash、ksh93 和 zsh 中是否匹配的更多详细信息。
重击
设置dotglob
选项。
$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero
还有更灵活的GLOBIGNORE
多变的,您可以将其设置为要忽略的以冒号分隔的通配符模式列表。如果未设置(默认设置),则如果dotglob
设置了该值,则 shell 的行为就像该值为空;如果.*
未设置该选项,则 shell 的行为就像该值为空。看文件名扩展在手册中。普遍目录.
和..
总是被省略,除非.
被模式显式匹配。
$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one
肯什93
设置FIGNORE
多变的。如果未设置(默认设置),shell 的行为就像该值为.*
。要忽略.
和..
,必须显式匹配它们(ksh 93s+ 2008-01-31 中的手册指出.
和..
始终被忽略,但这不再正确描述实际行为;编辑 这是固定的,因为)。
$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero
您可以将点文件包含在图案通过明确匹配它们。
$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero
要在目录为空时使扩展为空,请使用N
模式匹配选项:~(N)@(*|.[^.]*|..?*)
或~(N:*|.[^.]*|..?*)
。
兹什
设置dot_glob
选项。
% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero
.
和..
永远不会匹配,即使模式.
显式匹配前导。
% echo .*
..two .one
您可以使用以下命令将点文件包含在特定模式中:D
全局限定符。
% echo *(D)
..two .one none zero
添加N
glob 限定符以使扩展在空目录中显示为空:*(DN)
。
注意:根据、和变量的设置,您可能会以不同的顺序获得文件名扩展结果(例如,none
后跟.one
后跟) 。..two
LC_COLLATE
LC_ALL
LANG
答案2
#!/bin/bash
shopt -s dotglob
mv Foo/* Bar/
从man bash
点球如果设置,bash 包含以“.”开头的文件名在路径名扩展的结果中。
答案3
执行此操作的一个简单方法bash
是
mv {Foo/*,Foo/.*} Bar/
但这也会移动目录。
如果您想移动所有文件(包括隐藏文件)但不想移动任何目录,您可以使用 for 循环和测试。
for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;
答案4
我发现这对于 bash 很有效,并且不需要更改 shell 选项
mv sourcedir/{*,.[^.]*} destdir/
编辑:
因此,正如 G-man 所说,我最初的答案不符合 posix,并且与上面 ndemou 的答案几乎相同,但有一个更改,即使用大括号扩展来创建然后执行操作的字符串列表。这只是意味着您不需要cd
进入源目录。确实变化不大,但确实有所不同。
示例:假设您已经有以下布局。
$ tree -a
.
├── destdir
└── sourcedir
├── ..d1
├── ..d2
├── ..double
├── file-1
├── file-2
├── .hidden-1
├── .hidden-2
├── ...t1
└── ...t2
最初的问题仅提到带有单个句点的隐藏文件,但假设有些文件名称开头有两个或多个句点。您只需在大括号中添加一个附加表达式即可。然后我们就可以执行
mv sourcedir/{*,.[!.]*,..?*} destdir/
这扩展到以下内容:
mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/
您现在应该看到位于以下位置的所有文件目标目录:
$ tree -a
.
├── destdir
│ ├── ..d1
│ ├── ..d2
│ ├── ..double
│ ├── file-1
│ ├── file-2
│ ├── .hidden-1
│ ├── .hidden-2
│ ├── ...t1
│ └── ...t2
└── sourcedir
您可以在 bash 中使用大括号做一些非常酷的事情,并且在 4.x 中添加了更多功能。查看bash黑客一些漂亮的例子。