如何更改许多文件的符号链接路径?
How change symlink path for many files?
我被更改了目录名。
在这个目录中有数千个文件。
一些项目使用这个文件,项目有符号链接。
- 如何找到地址中包含文件夹名称的所有符号链接?
- 如何在自动模式下将所有这些符号链接更改为另一个路径?
如果只有 2 个 bash 脚本删除和创建新的 - 我会做,但你知道更简单的方法吗?
有点复杂,但是可以用find
,readlink
,检查symlink是否是相对的,和 sed
去除路径名中的 ..
(从 this answer 复制 1:1)。
(请注意,由于 symlinks 目标不再存在,因此最方便的方法(例如 readlink -f
)不可用。)
假设您的旧路径是 /var/lib/old/path
:
oldpath='/var/lib/old/path';
find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ...; fi;' \;
现在用 ln -sf
替换上面的 ...
(-f
覆盖现有的 link)。
假设您的新路径是 /usr/local/my/awesome/new/path
:
oldpath='/var/lib/old/path';
newpath='/usr/local/my/awesome/new/path';
find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ln -sf "'"$newpath"'${p:'${#oldpath}'}" "{}"; fi;' \;
注意 oldpath
和 newpath
必须是绝对路径。
另请注意,这会将所有相对符号 link 转换为绝对符号。
保持它们的相对性是可能的,但需要付出很多努力。
分解
对于那些关心一行地狱的实际含义的人:
find
- 一个很棒的可执行文件
/
- 搜索位置,在本例中为系统根目录
-type l
- 匹配符号 links
-execdir
- 对于每个匹配项 运行 在匹配文件的目录中执行以下命令:
bash
- 嗯,bash
-c
- 执行以下字符串(前导和尾随 '
已删除):
p="$(readlink "{}")";
- 从最内层开始:
"
- 开始一个字符串以确保不会发生扩展
{}
- 匹配文件名的占位符(-execdir
的特征)
"
- 结束字符串
readlink ...
- 找出 symlink 指向 的位置
p="$(...)"
- 并将结果存储在 $p
if [ "${p:0:1}" != "/" ]; then
- 如果 $p
的第一个字符是 /
(即 symlink 是绝对的),那么...
p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")";
- 将路径转换为绝对路径:
$(pwd)
- 当前目录(匹配文件所在的目录,因为我们使用的是 -execdir
)
/$p
- 在工作目录 的路径中附加一个斜线和 symlink 的目标
echo "$(pwd)/$p" |
- 将上面的内容通过管道传递给下一个命令
sed ...
- 解析所有 ..
,参见 here
p="$(...)"
并将结果存储回 $p
.
fi;
- 结束if
if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ];
- 如果 $p
以 $oldpath
开头
${p:0:'${#oldpath}'}
- $p
的子字符串,从位置 0
开始,长度为 $oldpath
:
${#oldpath}
- 变量的长度 $oldpath
'...'
- 必需,因为我们在 '
引号内
then
- 然后...
ln -sf
- link 象征性地覆盖现有文件,参数:
"'"$newpath"'${p:'${#oldpath}'}"
- 用 $newpath
替换 $p
的 $oldpath
部分(实际上从 $p
中删除与 $oldpath
一样多的字符是,并在其前面添加 $newpath
):
"
- 开始一个字符串
'
- 将 '
字符串参数结束为 bash -c
"
- 向其附加一个 "
字符串(其中发生变量扩展),包含:
$newpath
- $newpath
的值
"
- 将 "
字符串参数结束为 bash -c
'
- 向其附加一个 '
字符串,包含:
${p:
- p
的子字符串,起始于:
'
- 结束对 bash -c
的论证
${#oldpath}
- 将 $oldpath
的长度附加到它
'
- 向其附加另一个 '
-字符串
}
- 结束子字符串
"
- 结束字符串
"{}"
- link 文件,其路径保持不变
fi;
- 结束if
\;
- -execdir
的分隔符
我被更改了目录名。 在这个目录中有数千个文件。 一些项目使用这个文件,项目有符号链接。
- 如何找到地址中包含文件夹名称的所有符号链接?
- 如何在自动模式下将所有这些符号链接更改为另一个路径?
如果只有 2 个 bash 脚本删除和创建新的 - 我会做,但你知道更简单的方法吗?
有点复杂,但是可以用
find
,readlink
,检查symlink是否是相对的,和sed
去除路径名中的..
(从 this answer 复制 1:1)。
(请注意,由于 symlinks 目标不再存在,因此最方便的方法(例如readlink -f
)不可用。)
假设您的旧路径是/var/lib/old/path
:oldpath='/var/lib/old/path'; find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ...; fi;' \;
现在用
ln -sf
替换上面的...
(-f
覆盖现有的 link)。
假设您的新路径是/usr/local/my/awesome/new/path
:oldpath='/var/lib/old/path'; newpath='/usr/local/my/awesome/new/path'; find / -type l -execdir bash -c 'p="$(readlink "{}")"; if [ "${p:0:1}" != "/" ]; then p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; fi; if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ]; then ln -sf "'"$newpath"'${p:'${#oldpath}'}" "{}"; fi;' \;
注意 oldpath
和 newpath
必须是绝对路径。
另请注意,这会将所有相对符号 link 转换为绝对符号。
保持它们的相对性是可能的,但需要付出很多努力。
分解
对于那些关心一行地狱的实际含义的人:
find
- 一个很棒的可执行文件/
- 搜索位置,在本例中为系统根目录-type l
- 匹配符号 links-execdir
- 对于每个匹配项 运行 在匹配文件的目录中执行以下命令:bash
- 嗯,bash-c
- 执行以下字符串(前导和尾随'
已删除):p="$(readlink "{}")";
- 从最内层开始:"
- 开始一个字符串以确保不会发生扩展{}
- 匹配文件名的占位符(-execdir
的特征)"
- 结束字符串readlink ...
- 找出 symlink 指向 的位置
p="$(...)"
- 并将结果存储在$p
if [ "${p:0:1}" != "/" ]; then
- 如果$p
的第一个字符是/
(即 symlink 是绝对的),那么...p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")";
- 将路径转换为绝对路径:$(pwd)
- 当前目录(匹配文件所在的目录,因为我们使用的是-execdir
)/$p
- 在工作目录 的路径中附加一个斜线和 symlink 的目标
echo "$(pwd)/$p" |
- 将上面的内容通过管道传递给下一个命令sed ...
- 解析所有..
,参见 herep="$(...)"
并将结果存储回$p
.
fi;
- 结束if
if [ "${p:0:'${#oldpath}'}" == "'"$oldpath"'" ];
- 如果$p
以$oldpath
开头${p:0:'${#oldpath}'}
-$p
的子字符串,从位置0
开始,长度为$oldpath
:${#oldpath}
- 变量的长度$oldpath
'...'
- 必需,因为我们在'
引号内
then
- 然后...ln -sf
- link 象征性地覆盖现有文件,参数:"'"$newpath"'${p:'${#oldpath}'}"
- 用$newpath
替换$p
的$oldpath
部分(实际上从$p
中删除与$oldpath
一样多的字符是,并在其前面添加$newpath
):"
- 开始一个字符串'
- 将'
字符串参数结束为bash -c
"
- 向其附加一个"
字符串(其中发生变量扩展),包含:$newpath
-$newpath
的值
"
- 将"
字符串参数结束为bash -c
'
- 向其附加一个'
字符串,包含:${p:
-p
的子字符串,起始于:'
- 结束对bash -c
的论证
${#oldpath}
- 将$oldpath
的长度附加到它'
- 向其附加另一个'
-字符串}
- 结束子字符串"
- 结束字符串
"{}"
- link 文件,其路径保持不变
fi;
- 结束if
\;
--execdir
的分隔符