如何在目录上执行与 yes | cp -rf 等效的 mv 操作?

如何在目录上执行与 yes | cp -rf 等效的 mv 操作?

以下面的目录树为例,将内容移动directory/folderA到的最佳方法是什么directory

如果目标中存在同名文件,如何覆盖文件,例如:directory/folderA/2017/06/info.logdirectory/2017/06/info.log

directory
|-- folderA
|   |-- 2017
|   |   |-- 06
|   |
|   |-- 2016
|   |   |-- 12
|   |   |-- 11
|   |   |-- 10
|
|-- 2017
|   |-- 04
|   |-- 05
|   |-- 06
|
|-- 2016
|   |

答案1

您可以使用cp -l( --link,硬链接文件而不是复制):

cp -rfl folderA .
rm -rf folderA

只是mv移动,即将目录重命名为您的directory。对于在同一个文件系统内移动文件,mv使用rename()系统调用。如果源和目标位于不同的文件系统上,mv将使用cprm完成移动,但仍然首先删除目标,复制硬链接文件(-R)但不遵循符号链接(-P):

rm -f destination_path && \
cp -pRP source_file destination && \
rm -rf source_file

虽然您无法更改 的行为mvcp但命令本身更灵活,您确实应该使用它。使用cp-f会导致删除和创建目标中的单个文件,而不是先删除整个目标。

cp有限制,因为它只能覆盖 ( -f)、保存 ( -n) 或询问 ( -i)。如果您需要比较文件才能决定保留哪个文件,则需要rsync

如果您仍然需要使用rename()系统调用但要按要求完成合并​​目录的目标,则需要编写一个脚本来调用单个rename()文件的单独脚本。

答案2

首先,我使用以下方法创建了目录树

[root@localhost /tmp]# mkdir -pv directory/folderA/2017/06 directory/folderA/2016/{10..12} directory/2017/{04..06} directory/2016

然后我使用以下命令创建了示例文件:

[root@localhost /tmp]# touch directory/{,folderA}/2017/06/info.log

最后,我使用带有 --delete-after 的 rsync 来移动,而不是使用 rsync 的默认行为(即创建副本):

[root@localhost /tmp]# rsync --delete-after -a directory/folderA/ directory

注意:如果您希望在复制目录后删除目录,则需要在源目录后面加上尾随的“/”(即 directory/folderA/ 而不是 directory/folderA)。

当然,如果您确实想输入 mv 来获得所需的行为,您可以创建自定义 shell 函数。我并不提倡这样做,但这是可能的。虽然有点草率,但确实可能。

这是您可以添加到 ~/.bashrc 的自定义函数:

function mv() {
    if [[ "$@" =~ .*--delete-after.*-av*.* ]]; then
            rsync $@
    else
            command mv $@
    fi; }

然后通过注销并重新登录来调用更新的 ~/.bashrc - 或者 - 输入:

[root@localhost /tmp]# exec bash

现在,您可以使用以下任一方式测试您的自定义函数:

[root@localhost /tmp]# mv --delete-after -av directory/folderA/ directory

为了获得详细输出,

或者:

[root@localhost /tmp]# mv --delete-after -a directory/folderA/ directory

仅接收遇到的错误。

另外,您还可以通过在 cp 命令前面加上反斜杠来避免将 yes 传递给 cp -rf 命令,如下所示:

[root@localhost /tmp]# \cp -rf directory/folderA/* directory/

您使用管道传输“是”的原因是您可能在 ~/.bashrc 中有一个 cp 命令的别名,如下所示:

[root@localhost /tmp]# alias cp='cp -i'

您可以通过输入以下内容进行验证:

[root@localhost /tmp]# type cp

相关内容