如何“反转”rsync -L?

如何“反转”rsync -L?

rsync来自的标志的文档-L

-L, --copy-links 将符号链接转换为引用文件/目录

这个问题是关于如何“反转”最初使用rsync -L ....


对我来说,用一个简单的具体例子来解释“反向”的意思是最容易的。

设置

假设我有目录/tmp/SOURCE//tmp/TARGET/,如下所示:

$ /usr/bin/tree -aF /tmp/SOURCE/ /tmp/TARGET/
/tmp/SOURCE/
├── A.d/
│   ├── w
│   └── x
├── B.d/
│   └── z
├── C.d/
│   ├── w -> ../A.d/w
│   └── y -> ../A.d/x
└── D.l -> B.d/
/tmp/TARGET/

特别要注意以下细节:

  • 的内容/tmp/SOURCE/C.d是指向常规文件的相对符号链接/tmp/SOURCE/A.d
    • 符号链接/tmp/SOURCE/C.d/w及其引用的基本名称相同;
    • /tmp/SOURCE/C.d/y符号链接(即)的基本名称y与其引用对象(即x)的基本名称不同;
  • /tmp/SOURCE/D.l是一个相对符号链接/tmp/SOURCE/B.d
  • /tmp/TARGET/目前为空。

从这个初始状态,我运行本文标题中提到的命令,我想要“反转”的命令类型(如下文进一步解释):

$ rsync -L -a /tmp/SOURCE/C.d /tmp/SOURCE/D.l /tmp/TARGET

运行此命令后,/tmp/TARGET/看起来像这样:

$ /usr/bin/tree -aF /tmp/TARGET/
/tmp/TARGET/
├── C.d/
│   ├── w
│   └── y
└── D.l/
    └── z

特别注意的是,虽然在 Both/tmp/SOURCE/tmp/TARGET相对路径下

C.d/w
C.d/y
D.l/z

存在,只有下面的/tmp/TARGET才是“真实”路径。我所说的“真实路径”是$P指,粗略地说, 的输出readlink -f $P又是$P(或者更准确地说,${P:a})。例如

$ readlink -f /tmp/TARGET/C.d/w
/tmp/TARGET/C.d/w

$ readlink -f /tmp/SOURCE/C.d/w
/tmp/SOURCE/A.d/w

问题

在当前上下文中,我所说的“反转”之前的rsync -L命令基本上是将常规文件复制/tmp/TARGET/到它们的原件/tmp/SOURCE,留下结构/tmp/SOURCE不变。

特别是,在此“反向传输”之后,下面的符号链接/tmp/SOURCE应保持符号链接,并且应指向确切地与之前相同的指称。

我正在寻找一种方法来执行这种“反转”,其复杂性/难度与rsync -aL首先用于执行“正向”传输的命令相当。


这个简单示例的一个缺点是很简单人们很想用暴力来解决问题。例如

$ rsync /tmp/TARGET/C.d/w /tmp/SOURCE/A.d
$ rsync /tmp/TARGET/C.d/y /tmp/SOURCE/A.d/x
$ rsync /tmp/TARGET/D.l/z /tmp/SOURCE/B.d

IOW,在如此简单的情况下,这种强力方法并不比运行原始rsync -L传输困难多少。然而,一般来说,与原始传输相比,暴力策略的执行起来要困难得多。

此示例过于简单,因为源主机和目标主机相同。 一般来说,他们不会,因此,请避免依赖示例的此功能的解决方案。


FWIW,以下脚本创建了上面玩具示例的设置。

BASEDIR=/tmp/test1

# uncomment the following line before running this script a second time
# rm -rf $BASEDIR/SOURCE $BASEDIR/TARGET

mkdir -p $BASEDIR/SOURCE/{A,B,C}.d $BASEDIR/TARGET
touch $BASEDIR/SOURCE/{A.d/{w,x},B.d/z}
ln -s ../A.d/w $BASEDIR/SOURCE/C.d/w
ln -s ../A.d/x $BASEDIR/SOURCE/C.d/y
ln -s B.d $BASEDIR/SOURCE/D.l

答案1

有一些选项允许 rsync 在引用目录时不干扰远程上的符号链接,但它似乎没有选项不将文件的符号链接替换为真实文件。

因此,您可能要做的就是首先以某种方式保留 SOURCE 中文件的符号链接,例如通过重命名它们或将它们列出到文件中,然后执行 rsync 保留目录符号链接,然后恢复文件符号链接,从复制数据真实文件到恢复的符号链接,然后删除真实文件。这是一个潜在的脚本:

find /tmp/SOURCE -type l ! -xtype d -exec mv {} {}.lnk \;
cd /tmp/TARGET || exit
rsync -a -R --no-implied-dirs --keep-dirlinks . /tmp/SOURCE/
find /tmp/SOURCE -type l ! -xtype d |
while read fname
do base=${fname%.lnk}
   cp "$base" "$fname" 
   mv "$fname" "$base"
done

我让你正确处理奇怪的文件名。我不确定这-R --no-implied-dirs是否必要,但我会让你尝试一下。

答案2

我认为你不能直接在rsync. --keep-dirlinks( )选项-K将使符号链接目录保持不变,但符号链接文件仍将被覆盖。

我能找到的最接近的解决方案是一个小 ( bash) 脚本

( cd TARGET && find . -type f -print0 | sed 's!^./!!' ) |
    while IFS= read -d $'\0' -r f
    do
        s=$(readlink -f SOURCE/"$f")
        rsync -a TARGET/"$f" "${s:-f}"
    done

TARGET一次将每个文件放入一个文件中,检查其中的符号链接目标SOURCErsync直接应用于该文件。

相关内容