移动除一个文件外的所有文件

199

如何移动除一个文件之外的所有文件?我需要像这样的东西:

'mv ~/Linux/Old/!Tux.png ~/Linux/New/'

我想把旧的东西移到新的文件夹中,除了Tux.png以外。!符号表示否定。有没有什么工具可以完成这项工作?

14个回答

175

如果您使用bash并且已经设置了extglob shell选项(通常情况下是这样):

mv ~/Linux/Old/!(Tux.png) ~/Linux/New/

1
当我测试以下命令时出现了问题: mv ~/Linux/Old/!(Tux.png Tux1.png Tux2.png) ~/Linux/New/它清空了整个Old目录。这是怎么回事? - Léo Léopold Hertz 준영
11
尝试输入:~/Linux/Old/!(Tux.png|Tux1.png|Tux2.png)。该命令为Unix系统中的命令,用于在指定目录中查找不包括Tux.png、Tux1.png和Tux2.png文件的所有旧文件。 - Juliano
@Juliano 非常酷的命令!是否还有更多像OR和XOR这样的数学运算?我猜管道是用于AND。 - Léo Léopold Hertz 준영
有特定的数量吗?据我所知没有。你必须更清楚地说明你拥有哪些文件,想要移动哪些文件,否则很难确定需要键入的命令是什么。请注意,这些模式是正则表达式,它们在每个文件名上执行,而不是相反的方式。 - Juliano
4
对于ZSH用户,不要使用shopt命令(它将会返回"command not found"错误),而是把下面这行代码添加到你的.zshrc文件中:setopt extended_glob然后, glob语法也会相应地改变。因此,使用mv ~/path/to/source^(exception) ~/path/to/target/folder就可以了。 - Alex Xiong
显示剩余3条评论

119
将以下内容添加到你的 .bashrc 文件中。
shopt -s extglob

这扩展了正则表达式。 然后,您可以移动除一个文件以外的所有文件。

mv !(fileOne) ~/path/newFolder

与其他命令相关的异常

请注意,在复制目录时,正斜杠不能在名称中使用,这一点在Why extglob except breaking except condition?线程中已经提到:

cp -r !(Backups.backupdb) /home/masi/Documents/

所以在否定语前使用Backups.backupdb/是错误的,因为在移动目录时它存在被误用于其他命令以及可能会出现其他异常情况的风险。


3
这实际上是正确答案。我的回答完全错误;幸运的是,我只在一个文件夹中使用了它。这是Masi所展示方法的更多信息:http://wiki.bash-hackers.org/syntax/pattern。前往“扩展模式语言”并您将找到更多信息。感谢@paul-whittaker指出这个问题。 - mimoralea
这是一个旧答案,但仍然有效。我正在使用Ubuntu 18,extglob似乎已经默认启用(我没有shopt它)。我使用以下命令将当前目录中的所有文件移动到存档中,该存档也位于此目录中,不包括任何其他存档文件夹: mv !(arc*) archive_190629b - TonyG

80
我会选择传统的查找和xargs方法:
find ~/Linux/Old -maxdepth 1 -mindepth 1 -not -name Tux.png -print0 | 
    xargs -0 mv -t ~/Linux/New

-maxdepth 1会使其不进行递归搜索。如果您只关心文件,您可以使用-type f-mindepth 1会使结果中不包括~/Linux/Old路径本身。适用于任何文件名,包括包含嵌入式换行符的文件名。

一条评论指出,mv的-t选项可能是GNU扩展。对于没有此选项的系统

find ~/Linux/Old -maxdepth 1 -mindepth 1 -not -name Tux.png \
    -exec mv '{}' ~/Linux/New \;

2
因为它鼓励学习一个强大的工具,所以我给你点赞。请注意,对于带有空格的文件,这个方法不适用。考虑使用"find -print0 | xargs -0"或者放弃使用xargs:"find [你说的内容] -exec mv -t {} ~/Linux/New ;" - JasonSmith
1
如果您的mv命令没有-t选项,则可以使用“find ... -exec mv {} Linux/New ;”或“find ... | xargs -I {} mv {} Linux/New”。-t选项似乎是GNU扩展,这对于Linux来说很好,但可能不适用于其他地方。 - Rob Kennedy
@user637338 你所有的度量都是主观的,除了“正确”之外。从主观中得出客观结论似乎也不正确。我对复杂程度的看法是:find 命令应该成为在 Linux 上的日常必备命令,然后我的 find 命令行就几乎像自然语言一样易读。 - Johannes Schaub - litb
我只是想解释一下为什么我给你的答案打了低分,而给Masi的答案打了高分。即使在自然界中,简单也应该是好解决方案的指标之一。我认为这一点我们可以达成共识。问题在于,对于不同类型的人来说,简单意味着什么。将您的答案与此进行比较:“mv !(fileOne) ~/path/newFolder”,我会说从简单性的角度来看,后者更胜一筹。这就是我想要表达的,也许当时没有表述清楚。 - user637338
@user637338 我认为这个比较不公平 :) 它应该与 "shopt -s extglob; mv !(fileOne) ~/path/newFolder" 进行比较。 - Johannes Schaub - litb
显示剩余5条评论

37

我认为最简单的方法是使用反引号

mv `ls -1 ~/Linux/Old/ | grep -v Tux.png` ~/Linux/New/

编辑:

在使用别名时,使用反斜杠与ls一起使用,以防止其被别名覆盖。 例如,大多数情况下,ls被别名为ls --color。


mv `\ls -1 ~/Linux/Old/ | grep -v Tux.png` ~/Linux/New/
谢谢 @Arnold Roa

1
请问您能解释一下为什么在那里使用 grep -v 吗? - Léo Léopold Hertz 준영
1
grep 中的 -v 选项可以排除结果,就像除了 Tux.png 之外的所有内容。 - Rohail Abbas
1
这当然很直观,但上面的答案更好。例如,如果您正在编写脚本,这将要求您处于正确的目录中。 - nJGL
@nJGL 我们也可以在这里给出绝对路径,但由于问题中使用了主目录(~),所以我使用了主目录路径。 - Rohail Abbas
1
@RohailAbbas 好的,没问题。✌️ - nJGL

36

一个快速的方法是修改tux文件名,这样你的移动命令就不会匹配。

例如:

mv Tux.png .Tux.png

mv * ~/somefolder

mv .Tux.png Tux.png

请勿使用“*.”,因为这只会移动文件名中带有“.”的文件。只需使用“”即可。 - Juliano
1
如果你将它改为*,它也会删除你重命名的文件。 - John T
9
@John T:不,*通配符无法匹配以点号开头的文件。 - Bill Karwin

17

对于bash,这个回答是正确的。这里是zsh(我选择使用的shell)的语法:

mv ~/Linux/Old/^Tux.png ~/Linux/New/

需要设置 EXTENDED_GLOB shell 选项。


4
如果我们想要排除两个文件,应该怎么做? - mpen

15

我认为这样更加安全和方便,可以依赖于简单的动作排除特定的文件或目录。

ls -1 | grep -v ^$EXCLUDE | xargs -I{} mv {} $TARGET

这是忙碌盒子/ASH的最佳解决方案。 - Stuart Cardall
1
这个方法适用于我需要将除了几个文件夹以外的所有文件移动到另一个目录的情况。 - Umar Hayat
ls 命令的 -l 选项会在命令行中包含大量无关信息,并导致 mv 命令失败。 - jdhao
@jdhao 这不是 L,而是 1。 - alex.pilon
1
即使在最简单的Docker容器上也能运行。 - Diego Victor de Jesus

7
这个方法简单易记,并且对我很有效。 mv $(ls ~/folder | grep -v ~/folder/exclude.png) ~/destination 请注意,上面的命令中包含HTML标签,请保留。

非常有用。-v 表示 --invert-match。我认为对于多个术语,可能可以使用 grep -e,但我还没有弄清楚如何使用。 - cardamom
1
我尝试将这个应用到“grep -v”部分的更长列表中,但变得非常复杂,不得不寻求帮助。然而,这是一个有趣和有用的解决方案。https://unix.stackexchange.com/questions/708296/detailed-bash-script-with-cp-and-grep-will-not-work-with-spaces-in-filenames - cardamom

6
以下并不是百分之百的保证方法,也不应尝试用于脚本编写。但有时对于快速交互式Shell使用来说已经足够好了。一个文件文件通配符就像:

[abc]*

以 a、b 或 c 开头的所有文件都可以通过在首位插入 "^" 字符来否定匹配。

[^abc]*

我有时会用这个来不匹配"lost+found"目录,例如:

mv /mnt/usbdisk/[^l]* /home/user/stuff/.

当然,如果还有其他以l开头的文件,我必须在处理完这些文件后再处理。

5
怎么样:
mv $(echo * | sed s:Tux.png::g) ~/Linux/New/

但是你必须进入该文件夹。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接