如何将目录中的所有文件(包括隐藏文件)移动到另一个目录?

例如,如果我有一个文件夹“ Foo”,其中包含文件“ .hidden”和“ notHidden” ,如何将两个文件都移动到名为“ Bar”的目录?由于“ .hidden”文件停留在“ Foo”中,因此以下命令不起作用。

mv Foo/* Bar/


尝试一下。

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/


评论

Linux:如何将所有文件从当前目录移动到上级目录?

ah,我知道我应该在输入我的答案之前先刷新一下答案。非常有用的链接。

可悲的是,这个问题在这里结束了,因为我在SO上说应该移到这里或SU,所以当SU上已经有副本时,它当然移到了这里:)

就我个人而言,我认为* nix特定的问题和答案应该在SU上不合时宜。按照当前的规则,我们最终会在两者之间产生大量的内容冲突-就像这个问题一样。

#1 楼

Zsh

mv Foo/*(DN) Bar/




setopt -s glob_dots
mv Foo/*(N) Bar/


(如果知道目录不为空,请忽略(N)。 )

Bash

shopt -s dotglob nullglob
mv Foo/* Bar/


Ksh93

如果您知道目录不为空:

FIGNORE='.?(.)'
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/ -- {} +


Standard find

如果您不介意切换到源目录,请执行以下操作:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "
$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero
"' ../Bar/ {} + -type d -prune



这里有更多有关控制点文件是否匹配的详细信息在bash,ksh93和zsh中。

bash

设置dotglob选项。

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one


还有更多功能灵活的GLOBIGNORE变量,您可以将其设置为以冒号分隔的通配符模式列表,以将其忽略。如果未设置(默认设置),则如果设置了dotglob,则外壳的行为就像值是空的;如果未设置此选项,则外壳的行为就好像值是.*。请参见手册中的“文件名扩展”。除非.与模式明确匹配,否则将始终省略普遍存在的目录...

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero


Ksh93

设置FIGNORE变量。如果未设置(默认设置),则外壳的行为就像值是.*一样。要忽略...,必须对其进行显式匹配(ksh 93s + 2008-01-31中的手册指出,始终忽略...,但这不能正确描述实际行为)。

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero


可以通过显式匹配将点文件包含在模式中。

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero


如果目录为空白,请使用N模式匹配选项:~(N)@(*|.[^.]*|..?*)~(N:*|.[^.]*|..?*)

Zsh

设置dot_glob选项。

% echo .*
..two .one


...永远不会匹配,即使模式明确匹配前导.

% echo *(D)
..two .one none zero


您可以使用D glob限定符以特定的模式包含点文件。

q4312078q

添加N glob限定符以使扩展扩展为空在一个空目录中:*(DN)


注意:您可能会以不同顺序获得文件名扩展结果
(例如,none后跟.one,然后是..two
LC_COLLATELC_ALLLANG变量的设置上。

评论


为什么选择nullglob?比中止运行mv / Bar /命令更有意义的是,中止mv命令(例如fish,csh / tcsh,zsh(不带(N))执行或使用failglob进行bash)更有意义。

–StéphaneChazelas
16年2月21日在16:29

我会说您对GLOBIGNORE的描述不准确且具有误导性。将GLOBIGNORE设置为非空值会打开dotglob并使其生效。和..永远不会匹配(就像在其他明智的shell中一样,例如zsh,fish,pdksh和派生类),即使您随后将dotglob重新关闭。 (GLOBIGNORE = :; shopt -u dotglob; echo。*将不会输出。和..)。将GLOBIGNORE设置为。:..或。或:具有相同的效果。

–StéphaneChazelas
16-2-21在19:37



ksh93总是忽略。和..似乎已在ksh93k +(在其起作用的位置)和ksh93m(在其不再起作用的位置)之间中断。请注意,ksh93会从环境中获取FIGNORE的值是很糟糕的,因此,例如FIGNORE ='!(..)'env var可能会造成严重破坏。

–StéphaneChazelas
16年2月21日在21:05

zsh中的(DN)选项上是否有文档?找不到它。

–丰满
20年7月22日在13:17

@Plumpie这是两个glob限定词。我的答案中有指向文档的链接。

–吉尔斯'所以-不再是邪恶的'
20年7月22日在13:45

#2 楼

#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/


来自man bash



dotglob如果已设置,bash包含以'。'开头的文件名。在
路径名扩展的结果中。


评论


需要注意的是,如果目录为空,则此命令将返回错误代码(即使该命令实际上按预期执行)。

–吉尔斯'所以-不再是邪恶的'
11年1月24日在20:28

@Gilles,则错误将来自mv抱怨称为Foo / *的文件不存在。有趣的是,如果Foo是可搜索的,但不可读,并且其中有一个名为*的文件,则不会出错,该文件将被移动,但目录中的其他文件不会被移动。 bash具有failglob选项,因此它的行为更像zsh,fish或csh / tcsh,并且在无法扩展glob而不是将glob保持原样的虚假行为时,会中止该命令并显示错误。

–StéphaneChazelas
16-2-22在10:01



#3 楼

bash中执行此操作的一种简单方法是

mv {Foo/*,Foo/.*} Bar/


,但这也会移动目录。

如果要移动所有文件(包括隐藏文件)但不想移动任何目录,可以使用for循环和测试。

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;

评论


最简单的解决方案,因为它不需要记住第二个命令:)谢谢。

– aderchox
20-10-19在8:41

#4 楼

一种方法是使用find

find Foo/ -type f -exec mv -t Bar/ {} \+


-type f将find命令限制为查找文件。您应该研究-type-maxdepth-mindepthfind选项,以自定义命令来说明子目录。查找有一个冗长但非常有用的手册页。

评论


这样只会将常规文件移动到Foo /中,而不会移动子目录和其他文件。

–吉尔斯'所以-不再是邪恶的'
11年1月24日在20:29

#5 楼

尝试使用复制命令cp

$ cp -r myfolder/* destinationfolder


cp -r表示复制递归,因此将复制所有文件夹和文件。

可以使用删除命令rm删除文件夹:

$ rm -r myfolder


查看更多:将所有文件从目录移动到另一个。

评论


当您移动许多大文件时,这不是最好的方法,但是我想它会起作用。

– Cory Klein
2014年5月12日17:25

也许您使用圆点而不是星星?

– Vincent
19年3月21日在18:23

警告:这不会复制隐藏文件。星号*默认不包含隐藏文件。

–匿名
19/12/15在13:12



#6 楼

我发现这对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黑客以获取一些漂亮的示例。

评论


除了您添加了花括号(没有说明它们)之外,这基本上与ndemou的答案相同。但是(1)您的答案与名称以..开头的文件不匹配,并且(2)要与POSIX兼容,您应该使用!而不是^;即{* ,. [!。] *}。

– G-Man说“恢复莫妮卡”
19 Mar 6 '19 at 4:23

@ G-Man,对此感到抱歉。所以您是正确的,而我很遗憾没有看到ndemou的回应。他们几乎是同一回事。 1.感谢您指出我的版本不符合posix。 2.我正在使用括号扩展来创建字符串列表,然后外壳程序将使用这些字符串执行操作。这也意味着我不需要进入源目录来对文件进行操作,也不需要一遍又一遍地写出相同的文件路径来表示所有文件的路径。我将尽快更新示例,以使所有读者都能更好地了解我在说什么。

– cmndr sp0ck
19年3月7日在17:22



#7 楼

Rsync是另一种选择:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory


这是可行的,因为在rsync中尾随斜杠很重要,sourcedirectory/指目录的内容,而sourcedirectory指目录本身。

这种方法的缺点是rsync只会在移动后清理文件,而不会清理目录。因此,您将剩下一个空的源目录树。有关解决方法,请参见:

使用rsync移动文件并删除目录?

因此,这对于移动操作可能不是最佳选择,但对于复制操作而言却非常有用。

#8 楼

回答bash / fish

这是使用通配符的一种方法:

.[!.]* ..?*将匹配除...以外的所有隐藏文件

.[!.]* ..?* *将匹配除...以外的所有文件(是否隐藏)

并回答该问题的特定示例,您需要cd foo && mv .[!.]* ..?* * ../bar

解释

.[!.]*匹配以一个点开头的文件名,后跟任何字符,除了该点之外还可以选择后面跟任意字符串。这足够接近,但是会丢失以两个点开头的文件,例如..foo。要包含此类文件,我们添加..?*,该文件与以两个点开头的文件名匹配,后跟任意字符,还可以选择后跟任意字符串。

Test

您可以测试这些通配符使用以下命令。我已经成功地尝试了它们。他们在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


#9 楼

对于最少的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


评论


这对我有帮助2> / dev / null

– Ifeanyi Amadi
20 Mar 25 '20 at 19:43

与该mv {Foo / *,Foo /.*}结合使用时,Bar / 2> / dev / null会产生所需的结果。 2> / dev / null在后台运行该命令,因此可以忽略上的管道错误。和..

– Ifeanyi Amadi
20 Mar 25 '19:43



#10 楼

您也许还可以找到带有反引号的grep并进行grep选择,以选择move命令的文件。将这些内容传递到mv。

即对于隐藏文件

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden


So

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会停止查找子目录。

#11 楼

从此答案中得到启发:

不复制文件...

rsync -ax --link-dest=../Foo/ Foo/ Bar


注意事项:


--link-dest路径必须是绝对路径或相对于DESTINATION的路径(在示例中为Bar

您必须将/放在SOURCE之后(在示例中为Foo/),否则
将复制SOURCE文件夹而不是其内容。


#12 楼

简短的答案:
这是最可靠的方法。它可以消化任意数量的文件:
find folder2 -name '*.*' -exec mv {} folder \;
-exec运行任何命令,{}插入找到的文件名,\;标记exec命令的结尾。
感谢Karl Bielefeldt:https:// stackoverflow.com/a/11942473/4845952