如何使用“mv”命令移动除特定目录外的文件?

61

我想知道如何移动目录中除特定目录外的所有文件(由于'mv'命令没有'--exclude'选项)?


请查看此链接:http://unix.stackexchange.com/questions/2020/command-line-mv-exclusion-list - Madhur Ahuja
12个回答

110
假设目录结构如下:
|parent
    |--child1
    |--child2
    |--grandChild1
    |--grandChild2
    |--grandChild3
    |--grandChild4
    |--grandChild5
    |--grandChild6

我们需要移动文件,以便它看起来像这样:

|parent
    |--child1
    |   |--grandChild1
    |   |--grandChild2
    |   |--grandChild3
    |   |--grandChild4
    |   |--grandChild5
    |   |--grandChild6
    |--child2

在这种情况下,您需要排除两个目录child1child2,并将其余目录移动到child1目录中。
使用:
mv !(child1|child2) child1

这将把其余的所有目录移动到child1目录中。

26
提示:请注意,使用此模式需要依赖于 extglob。您可以使用 shopt -s extglob 命令来启用它(如果您想要默认开启 extended globs,您可以将 shopt -s extglob 添加到 .bashrc 中)。 - Boris D. Teoharov
19
当我尝试运行这个命令时,一直出现“-bash: !: event not found”的错误提示。请问如何解决? - FilBot3
3
啊,刚刚意识到上面的评论是针对bash所必需的。 - FilBot3
1
当除了被忽略的目录之外没有其他目录时,如何强制执行此操作? mv -f 似乎不起作用。我通过创建一个临时目录来解决它,这样总共有三个目录,然后移动所有目录,最后删除临时目录。很丑陋! - Michahell
请注意,如果您写入例如 mv !(child1/) grandChild*,则此方法将无法正常工作 - 要排除的目录名称不得包含尾部斜杠! - Jo Mo
显示剩余3条评论

6

由于find命令有排除选项,因此可以使用find + xargs + mv命令:

find /source/directory -name ignore-directory-name -prune -print0 | xargs -0 mv --target-directory=/target/directory

请注意,这几乎是从find手册复制过来的(我认为使用mv --target-directory比cpio更好)。

5

首先获取文件和文件夹的名称,并排除您不需要的内容:

ls --ignore=file1 --ignore==folder1 --ignore==regular-expression1 ...

然后将筛选过的名称作为第一个参数传递给 mv ,第二个参数将是目标位置:

mv $(ls --ignore=file1 --ignore==folder1 --ignore==regular-expression1 ...) destination/

2

这并不完全符合您的要求,但可能可以胜任:

mv the-folder-you-want-to-exclude somewhere-outside-of-the-main-tree
mv the-tree where-you-want-it
mv the-excluded-folder original-location

基本上,将被排除的文件夹从较大的树中移出以进行移动。
因此,如果我有a/,我想要排除a/b/c/*
mv a/b/c ../c
mv a final_destination
mkdir -p a/b
mv ../c a/b/c

或者类似这样。否则,您可能需要使用find来帮助您。


如果您要移动的文件位于根目录中怎么办?例如,有些系统只允许用户访问一个目录(一些云IDE是很好的例子)。也许有人想将所有内容移动到子目录中。这样是行不通的。 - Kallaste
1
正如我六年前所说,答案并没有准确描述所要求的内容,而且它只有可能完成任务。对于大多数情况,它应该可以工作;当然,你的情况是个例外。 - Thanatos
你说得对,确实不是这样的。但我的观点并不是它不是被要求的,而是在某些情况下它可能不起作用。我的例子只是一个假设,用来证明这一点。 - Kallaste

2
将您的目录重命名为隐藏目录,以便通配符无法看到它:
mv specific_dir .specific_dir 
mv * ../other_dir

1

这将移动当前目录及其子目录中不在./exclude/目录中的所有文件到/wherever...

find -E . -not -type d -and -not -regex '\./exclude/.*' -exec echo mv {} /wherever \;

这将忽略目录结构,将子目录中的所有文件复制到一个平面文件夹结构中。 a/b/c/ -> /任何地方 a/b.txt -> /任何地方 - Govinnage Rasika Perera
我得到了“未知谓词‘-E’” - Marecky

1
ls | grep -v exclude-dir | xargs -t -I '{}' mv {} exclude-dir

8
您是否希望在您的仅包含代码的答案中添加一些解释?这将有助于打破“StackOverflow是一个免费的代码撰写服务”的误解。此外,请查看这里以改善外观:https://stackoverflow.com/editing-help - Yunnosch

0
受 @user13747357 的 答案 启发。
首先,您可以使用 ls 命令列出文件,并按以下方式对其进行过滤:
ls | egrep -v '(dir_name|file_name.ext)'

然后,您可以运行以下命令来移动文件,但排除特定的文件:

mv $(ls | egrep -v '(dir_name|file_name.ext)') target_dir

* 注意,我在特定目录中测试了这个。跨目录操作应该更加小心执行 :)

0

假设你的目录是

.
├── dir1
│    └── a.txt
├── dir2
│    ├── b.txt
│    └── hello.c
├── file1.txt
├── file2.txt
└── file3.txt

你需要将file1 file2 file3放入dir2中。

你可以使用mv $(ls -p | grep -v /) /dir2来完成它,因为

ls -p | grep -v /会打印出当前工作目录中除了目录以外的所有文件。


0
#!/bin/bash

touch apple  banana  carrot  dog  cherry

mkdir fruit

F="apple  banana  carrot  dog cherry"

mv ${F/dog/} fruit

# 这将从列表F中删除“dog”,因此它仍然在当前目录中,而不是移动到“fruit”


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