我有一个 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 个参数:
- 要执行符号链接批量重命名的目录
- 旧模式。这
link1
是将被替换的旧模式 - 新的图案。这是将要替换的
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 % {}" \;