如何将目录中的所有文件(包括隐藏文件)移动到另一个目录?
例如,如果我有一个文件夹“ Foo”,其中包含文件“ .hidden”和“ notHidden”,如何将这两个文件都移动到名为“ Bar”的目录中?由于“ .hidden”文件保留在“ Foo”中,因此以下内容不起作用。
mv Foo/* Bar/
自己尝试。
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
如何将目录中的所有文件(包括隐藏文件)移动到另一个目录?
例如,如果我有一个文件夹“ Foo”,其中包含文件“ .hidden”和“ notHidden”,如何将这两个文件都移动到名为“ Bar”的目录中?由于“ .hidden”文件保留在“ Foo”中,因此以下内容不起作用。
mv Foo/* Bar/
自己尝试。
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
Answers:
mv Foo/*(DN) Bar/
要么
setopt -s glob_dots
mv Foo/*(N) Bar/
((N)
如果知道目录不为空,请忽略。)
shopt -s dotglob nullglob
mv Foo/* Bar/
如果您知道目录不为空:
FIGNORE='.?(.)'
mv Foo/* Bar/
for x in Foo/* Foo/.[!.]* Foo/..?*; do
if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done
如果您愿意让mv
命令即使成功执行也返回错误状态,则简单得多:
mv Foo/* Foo/.[!.]* Foo/..?* Bar/
find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +
如果您不介意切换到源目录:
cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune
这是有关控制bash,ksh93和zsh中的点文件是否匹配的更多详细信息。
设置dotglob
选项。
$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero
还有一个更灵活的GLOBIGNORE
变量,您可以将其设置为以冒号分隔的通配符模式列表,以将其忽略。如果未设置(默认设置),则外壳程序的行为就像设置了该值时为空dotglob
,.*
如果该选项未设置则为该值。请参见手册中的“ 文件名扩展 ”。除非目录.
与模式明确匹配..
,否则将始终省略普遍目录和.
。
$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one
设置FIGNORE
变量。如果未设置(默认设置),则外壳的行为就像该值是.*
。要忽略.
和..
,必须对其进行显式匹配(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
glob限定符以特定模式包含点文件。
% echo *(D)
..two .one none zero
添加N
glob限定词以使扩展在一个空目录中为空:*(DN)
。
注意:您可能会在不同的顺序文件名扩展的结果(例如,none
接着.one
后面..two
)根据您的设置LC_COLLATE
,LC_ALL
以及LANG
变量。
nullglob
呢 与运行没有意义的命令相比,中止mv
命令(例如fish,csh / tcsh,zsh(无(N)
)do或使用failglob进行bash)更有mv /Bar/
意义。
.
和..
(在其他合理的炮弹一样的zsh,鱼,pdksh程序和衍生品等)永远不会匹配即使您关闭dotglob背过之后。(GLOBIGNORE=:; shopt -u dotglob; echo .*
不会输出.
和..
)。将GLOBIGNORE设置为.:..
或.
或:
具有相同的效果。
ksh93
总是忽略.
并且..
似乎在ksh93k+
(它起作用的地方)和ksh93m
(不再起作用的地方)之间被打破了。请注意,这样做很糟糕,因为它ksh93
会从环境中获取FIGNORE的值,因此FIGNORE='!(..)'
,例如env var可能会造成破坏。
#!/bin/bash
shopt -s dotglob
mv Foo/* Bar/
man bash
dotglob(如果设置),bash包含以“。”开头的文件名。扩展路径名的结果。
mv
抱怨所调用的文件Foo/*
不存在。有趣的是,如果Foo
可搜索但不可读,并且其中有一个文件被调用*
,则不会出错,该文件将被移动,但目录中的其他文件不会被移动。bash
有一个failglob
选项,因此它的行为更像zsh
,fish
或csh
/,tcsh
并且当无法扩展glob而不是将glob保持原样的虚假行为时,中止命令并显示错误。
尝试复制命令cp
:
$ cp -r myfolder/* destinationfolder
cp -r
表示复制递归,因此将复制所有文件夹和文件。
您可以使用remove命令rm
删除文件夹:
$ rm -r myfolder
查看更多:将所有文件从一个目录移动到另一个目录。
Rsync是另一种选择:
rsync -axvP --remove-source-files sourcedirectory/ targetdirectory
之所以起作用,是因为在rsync中尾部的斜杠很重要,它sourcedirectory/
指的是目录的内容,而sourcedirectory
指目录本身。
这种方法的缺点是rsync仅在移动后清理文件,而不清理目录。因此,您将剩下一个空的源目录树。有关解决方法,请参见:
因此,尽管这对于移动操作可能不是最佳选择,但对于复制操作而言却非常有用。
扑食鱼的答案
这是使用通配符的一种方法:
.[!.]* ..?*
将匹配所有隐藏文件,除了.
和..
.[!.]* ..?* *
将匹配所有文件(是否隐藏),除了.
和..
并回答这个问题的特定示例 cd foo && mv .[!.]* ..?* * ../bar
说明
.[!.]*
匹配以一个点开头的文件名,然后是任何字符,除了该点之外还可以选择后面跟任意字符串。这足够接近,但是会丢失以两个点开头的文件,例如..foo
。为了包括此类文件,我们添加..?*
了与文件名匹配的文件名,文件名以两个点开头,后跟任意字符,并可选地后跟任意字符串。
测试
您可以使用以下命令测试这些通配符。我已经成功地尝试了它们。他们在sh,zsh,xonsh下失败。
mkdir temp
cd temp
touch a .b .bc ..c ..cd ...d ...de
ls .[!.]* ..?*
# you get this output:
.b .bc ..c ..cd ...d ...de
# cleanup
cd ..
rm -rf temp
您也许还可以找到带有反引号的grep并进行grep选择,以选择move命令的文件。将它们传递到mv。
即对于隐藏文件
find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden
所以
mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar
仅将选定的隐藏文件移动到Bar
:
mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar
从“。”开始将Foo中的所有文件移动到Bar。egrep命令中的命令用作通配符,不带方括号。
该^
特性可以确保匹配从行的开头开始。
egrep
模式匹配的一些细节可以在这里找到。
使用maxdepth 1
停止查找进入子目录。
我发现这对于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/
现在您应该看到位于destdir的所有文件:
$ tree -a
.
├── destdir
│ ├── ..d1
│ ├── ..d2
│ ├── ..double
│ ├── file-1
│ ├── file-2
│ ├── .hidden-1
│ ├── .hidden-2
│ ├── ...t1
│ └── ...t2
└── sourcedir
您可以在bash中使用花括号来做一些非常酷的事情,在4.x中甚至可以添加更多内容。查看bash黑客以获取一些漂亮的示例。
cd
进入源目录来对文件进行操作,也不需要一遍又一遍地写出相同的文件路径来表示所有文件的路径。我将尽快更新示例,以使所有读者都能更好地了解我在说什么。
对于最少的 Linux发行版,以下应该可以工作。首先,执行全部基本移动(丢失所有隐藏文件)。然后,将所有隐藏文件(包括.
和..
将不会实际移动)。
mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null
注意:如果没有可见的内容,则第一个命令将产生一条错误消息。第二个命令总是产生一个错误,说它不能移动.
和..
。这样,只需将错误传送到/dev/null
(如图所示)。
如果您需要将其作为单线使用,只需将它们与分号结合使用:
mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null