例如,如果我有一个文件夹“ Foo”,其中包含文件“ .hidden”和“ notHidden” ,如何将两个文件都移动到名为“ Bar”的目录?由于“ .hidden”文件停留在“ Foo”中,因此以下命令不起作用。
mv Foo/* Bar/
尝试一下。
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
#1 楼
Zshmv 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_COLLATE
,LC_ALL
和LANG
变量的设置上。评论
为什么选择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
,-mindepth
和find
选项,以自定义命令来说明子目录。查找有一个冗长但非常有用的手册页。评论
这样只会将常规文件移动到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
评论
Linux:如何将所有文件从当前目录移动到上级目录?ah,我知道我应该在输入我的答案之前先刷新一下答案。非常有用的链接。
可悲的是,这个问题在这里结束了,因为我在SO上说应该移到这里或SU,所以当SU上已经有副本时,它当然移到了这里:)
就我个人而言,我认为* nix特定的问题和答案应该在SU上不合时宜。按照当前的规则,我们最终会在两者之间产生大量的内容冲突-就像这个问题一样。