递归批量更新符号链接

递归批量更新符号链接

我有一个 Web 应用,其中的子目录中有很多符号链接。我需要将应用移动到另一个目录结构,并且需要更新所有符号链接以指向新路径。例如:

旧目录:/home/user/public_html/dev
新目录:/home/user/public_html/qa
旧符号链接:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
新符号链接:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

问题是,这些文件分散在各个目录中。我如何从根目录递归搜索并重新创建指向 的所有符号/dev/链接/qa/

答案1

这个 bash 命令应该可以帮你完成这个任务:

find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' -printf 'ln -nsf "$(readlink "%p" | sed s/dev/qa/)" "$(echo "%p" | sed s/dev/qa/)"\n' > script.sh

它用于find识别qa目录中所有文件,这些文件是目录中目标的符号链接dev,并且对于每个文件,它都会打印出一个 bash 命令,该命令会将链接替换为指向 中的等效路径的链接qa/。运行此命令后,只需使用以下命令执行生成的脚本

bash script.sh

您可能需要先手动检查它以确保它正常工作。

为了便于阅读,下面是上述命令的更详细版本find(尽管在实践中我不一定会这样写):

SRC_DIR="/home/user/public_html/qa"
OLD_TARGET="/home/user/public_html/dev"
SUB="s/dev/qa/"

find $SRC_DIR -type l \
  -lname "$OLD_TARGET/*" -printf \
  'ln -nsf "$(readlink "%p"|sed $SUB)" "$(echo "%p"|sed $SUB)"\n'\
 > script.sh

答案2

以防其他人在搜索解决方案时发现这一点:创建一个名为“linkmod.sh”的文件,其中包含:

#!/bin/sh
PATTERN1=`echo "$2"`
PATTERN2=`echo "$3"`
LINKNAME=`echo "$1"`
OLDTARGET=`readlink "$1"`
NEWTARGET=`echo "$OLDTARGET" \
| sed -e 's/'"$PATTERN1"'/'"$PATTERN2"'/'`
echo ln -nsf "$NEWTARGET" "$LINKNAME"

然后运行

find . -type l -print0 | xargs -0IX echo linkmod.sh X "pattern1" "pattern2"

如果需要,您当然可以在 find 中使用 -lname 选项。

注意:在 sed 中,你必须在模式中任何需要 \ 的字符前使用 2x \,因为 echo 会删除一个。例如

find . -type l -print0 | xargs -0IX echo linkmod.sh X "folder\\ name\\/file" "folder2\\ name\\/file"

echo如果 ln 命令正确,请从最后一行删除。

答案3

我创建了一个 bash 脚本link_rename.sh,用于递归重命名给定目录中的符号链接

#! /bin/bash

DIR=$1
OLD_PATTERN=$2
NEW_PATTERN=$3

while read -r line
do
    echo $line
    CUR_LINK_PATH="$(readlink "$line")"
    NEW_LINK_PATH="$CUR_LINK_PATH"  
    NEW_LINK_PATH="${NEW_LINK_PATH/"$OLD_PATTERN"/"$NEW_PATTERN"}"
    rm "$line"
    ln -s "$NEW_LINK_PATH" "$line"
done <<< $(find "$DIR" -type l)

它可以执行为link_rename.sh /home/human/dir link1 link2

该脚本有 3 个参数:

  1. 要执行符号链接批量重命名的目录
  2. 旧模式。这link1是将被替换的旧模式
  3. 新的图案。这是将要替换的link2新图案link1

该脚本递归读取目录中的所有符号链接find "$DIR" -type l 并逐行处理。

$line是需要重命名的符号链接

CUR_LINK_PATH是老路

NEW_LINK_PATH是通过在旧链接路径中执行字符串替换获得的。

旧的符号链接被删除,并使用创建新的符号链接ln -s "$NEW_LINK_PATH" "$line"

答案4

我在尝试将 PHP fpm 的符号链接从版本 8.0 更改为 8.1 时遇到了这个问题。这个命令对我来说很有效,没有太多麻烦。

find /etc/php/8.1/fpm/conf.d -type l -lname '/etc/php/8.0/mods-available/*' -exec bash -c "readlink {} |sed s/8.0/8.1/| xargs -I % ln -nsf % {}" \;

相关内容