如何更改许多文件的符号链接路径?

时间:2015-06-24 07:21:09

标签: linux bash ln

我更改了目录名称。 在这个目录中有数千个文件。 有些项目使用这个文件,项目上有符号链接。

  1. 如何查找所有符号链接,其地址中有文件夹名称?
  2. 如何在自动模式下将所有这些符号链接更改为另一个路径?
  3. 如果只有2个bash脚本用删除和创建新 - 我会这样做,但你可能知道更简单的方法吗?

1 个答案:

答案 0 :(得分:11)

  1. 它有点复杂,但可以使用findreadlink来检查,以检查符号链接是否相对,以及sed摆脱路径名中的..(从this answer复制1:1) (请注意,由于符号链接目标不再存在,大多数方便的方法(例如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;' \;
    
  2. 现在用...ln -sf替换上面的-f以覆盖现有链接。) 假设您的新路径为/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;' \;
    
  3. 请注意,oldpathnewpath必须是绝对路径 另请注意,这会将所有相对符号链接转换为绝对符号 可以让他们保持相对,但只需付出很多努力。

    分解

    对于那些关心一线地狱实际意味着什么的人:

    • find - 一个很酷的可执行文件
    • / - 搜索的位置,在本例中为系统根目录
    • -type l - 匹配符号链接
    • -execdir - 对于每个匹配,在匹配文件的目录中运行以下命令:
      • bash - 好吧,bash
      • -c - 执行以下字符串(删除前导和尾随'):
        • p="$(readlink "{}")"; - 从内心开始:
          • " - 启动字符串以确保不会发生扩展
          • {} - 匹配文件名称的占位符(-execdir的功能)
          • " - 结束字符串
          • readlink ... - 找出符号链接指向的位置
          • p="$(...)" - 并将结果存储在$p
        • if [ "${p:0:1}" != "/" ]; then - 如果$p的第一个字符是/(即符号链接是绝对的),那么......
        • p="$(echo "$(pwd)/$p" | sed -e "s|/\./|/|g" -e ":a" -e "s|/[^/]*/\.\./|/|" -e "t a")"; - 将路径转换为绝对路径:
          • $(pwd) - 当前目录(匹配文件所在的位置,因为我们正在使用-execdir
          • /$p - 将斜杠和符号链接的目标附加到工作目录的路径
          • 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 - 以符号方式链接并使用参数覆盖现有文件:
          • "'"$newpath"'${p:'${#oldpath}'}" - 将$oldpath的{​​{1}}部分替换为$p(实际上从$newpath移除尽可能多的字符$p,并在其前加$oldpath):
            • $newpath - 开始一个字符串
            • " - 结束' - 字符串参数'
            • bash -c - 向其附加" - 字符串(其中发生变量扩展),包含:
            • " - $newpath
            • 的值
            • $newpath - 结束" - 字符串参数"
            • bash -c - 在其中添加' - 字符串,其中包含:
            • ' - ${p:的子字符串,从:
            • 开始
            • p - 结束'
            • 的论点
            • bash -c - 将${#oldpath}的长度附加到
            • $oldpath - 向其添加另一个' - 字符串
            • ' - 结束子字符串
            • } - 结束字符串
          • " - 链接文件,其路径保持不变
        • "{}" - 结束fi;
    • if - \;
    • 的分隔符