如何在符号链接递归中找到中间体?

如何在符号链接递归中找到中间体?

是否有非递归readlink -f/realpath替代方案可以输出绝对符号链接目标?也欢迎更多 POSIX 兼容的解决方案。

我的 shell 脚本中有一个功能块,如下所示:

set FILES
# addFile adds a file to the FILES list. If file is a symlink,
# it will also find and add the destination.
addFile() {
    file="$1"
    # Check if file is already included in list
    echo "$FILES" | grep -q "$file" && return
    FILES="$FILES $file"
    if [ -L $file ]; then
        addFile $(realpath $file)
        #addFile $(readlink $file)
    fi
}

我在一个脚本中使用此函数,该脚本从文件系统收集二进制文件和库文件。但我预见到这段代码有一个问题:

  1. 我的第一次尝试使用了readlink,但这返回了相对于 的符号链接解析路径$file,因此在这些路径上执行的任何操作都会失败。 (现在已注释掉,但仍在代码中)(请参阅下面的小编辑)
  2. 之后,我realpath按照建议使用了man readlink。几乎可以用了。

现在,我想要执行的操作可以正常工作了。但是,最终结果是,我将复制 initramfs 中的所有二进制文件、库和符号链接。如果有任何递归符号链接,则只会包含顶层和目标,而不会包含中间的符号链接。因此,符号链接被破坏了。

我创建了一个小提琴来演示这个问题。link-to-link1指向link1,它指向file1。最终结果link1丢失并被link-to-link1破坏。

编辑;澄清问题

在以下一组符号链接上运行上述函数时:

# Contents of ~/test/src
file0
file1
link0 -> file0
link0.1 -> file0
link1 -> file1
link-to-link1 -> link1

和:

copy="link-to-link1 link0 link0.1"
for sf in $copy; do
    addFile ~/test/src/$sf
done;
cp -av $FILES ~/test/dst

$copy您会发现仅复制了3 个链接和 2 个文件。然而,中间环节link1缺失且link-to-link1已损坏。

link1我也希望找到该脚本。请记住,在运行此脚本的环境中,文件和符号链接的位置必须是绝对的。

小修改

添加另一个小提琴为了演示相对路径的失败,使用readlink.仅复制符号链接,并且缺少目标。

答案1

如果我理解正确,对于给出的示例,您想要link1文件link-to-link1.您可以使用 GNUfind-printf和来获得%l

$ find . -type l -printf '%p -> %l\n'
./link0.1 -> file0
./link1 -> file1
./link0 -> file0
./link-to-link1 -> link1

由于需要 的绝对路径link1作为 的输出/path/to/link-to-link1,可能是包含并连续运行/ 的cd目录:link-to-link1readlinkrealpath

(
cd "$(dirname "$file")"
realpath -s "$(readlink "$file")"
)

realpath -s不解析符号链接,但会打印绝对路径。

例如:

~ file=/tmp/foo/link-to-link1
~ (cd "$(dirname "$file")"; realpath -s "$(readlink "$file")")
/tmp/foo/link1

这也适用于绝对路径的链接:

~ file=/tmp/foo/link2
~ ln -sfv /tmp/foo/link1 "$file"
'/tmp/foo/link2' -> '/tmp/foo/link1'
~ (cd "$(dirname "$file")"; realpath -s "$(readlink "$file")")
/tmp/foo/link1

相关内容