我刚开始使用 BASH,所以我可以将一个目录的所有内容移动到另一个目录。但问题是,我期望它合并目录。我正在使用 cron 作业来运行此脚本。
#!/bin/bash
shopt -s dotglob nullglob
mv mv_schedule/* public_html/
来源:(/mv_schedule/
包含文件夹/文件)
/files/
4.html
5.html
/assets/
sitemap.xml
目标:(/public_html/
先前的文件夹已经存在)
/files/
1.html
2.html
3.html
/assets/
sitemap.xml
所以我想要的是,将这些目录中的所有新文件/mv_schedule/
与中的文件合并/public_html/
,并将其中已经存在的文件替换为来自的文件/mv_schedule/
。
当我使用当前脚本尝试此操作时,它当前通过电子邮件返回此错误:
mv: cannot move `mv_schedule/assets' to `public_html/assets': Directory not empty
我怎样才能解决这个问题?
答案1
错误消息告诉您,它无法 mv asset 目录,因为该目录中有文件。mv 目录意味着进行复制,然后删除它,并且无法删除它,因为它仍包含一些文件。这意味着您还应该 mv asset 内的文件,甚至应该 mv asset 内的子目录和子目录中的文件(如果存在)。但是发出的 mv 命令只能复制(和删除)mv_schedule 目录中的内容,而不能复制 mv_schedule 内子目录(如 asset)中的内容。
您需要的是一个命令,该命令会将目录树向下移动到最后一个叶子节点并进行复制,类似于 rm、chmod、chown 中的 -r 或 -R 选项。但是,mv 没有这样的选项,因此您必须使用 find 命令,该命令会从您指定的根节点向下移动到整个目录树,然后执行您指定的操作。对于您的情况,合适的命令是:
SOURCE_DIR=$1
TARGET_DIR=$2
find $SOURCE_DIR -name '*' -type f -exec mv -f {} $TARGET_DIR \;
这会将所有文件堆积到单个目标目录中。它假定您将源目录和目标目录作为输入行参数传递给 bash 脚本。-f 选项可防止在覆盖时要求确认,您可以将其更改为 -n(不覆盖)或 -i(覆盖前询问)。
如果您希望保留目录结构,请记住 cp 命令可以降低目录树,因此您可以使用该命令,然后使用 rm,因为该命令也可以降低目录树。一组可能的命令是:
SOURCE_DIR=$1
TARGET_DIR=$2
cp -a $SOURCE_DIR $TARGET_DIR
rm -rf $SOURCE_DIR
注意 cp 中的 -a 选项:它保留时间戳和所有权。如果您不关心这些事情,您可以改用 -R。
答案2
有一个更通用的这个问题的讨论在 Unix 部分。
-l
您可以使用cp命令,创建硬链接同一文件系统上的文件,而不是完整数据副本。以下命令将文件夹复制到已包含名为 的目录source/folder
的父文件夹 ( ) 。destination
folder
cp -rl source/folder destination
rm -r source/folder
笔记:
- 根据您的需要,您可能还想使用
-P
(--no-dereference
- 不取消引用符号链接)或-a
(--archive
- 保留所有元数据,还包括选项)。-P
- 虽然涉及两个“I/O”步骤,但这些步骤都是相对简单的元数据操作,不涉及任何“数据”传输。因此,此方法比 cp(无
-l
)或基于 rsync 的解决方案快几个数量级。 - 这确实不是如果源文件夹和目标文件夹位于不同的文件系统上,则可以工作