鉴于此示例:
mkdir a
ln -s a b
ln -s b c
ln -s c d
如果我执行:
ls -l d
它将显示:
d -> c
有没有办法ls
或者其他 Linux 命令来显示d -> c -> b -> a
?
答案1
只需使用namei
:
$ namei d
f: d
l d -> c
l c -> b
l b -> a
d a
答案2
readlink -e <link>
readlink [选项]... 文件
- -e, --canonicalize-existing
通过递归跟踪给定名称的每个组件中的每个符号链接来规范化,所有组件必须存在
$ mkdir testlink
$ cd testlink
pjb@pjb-desktop:~/testlink$ ln -s c b
pjb@pjb-desktop:~/testlink$ ln -s b a
pjb@pjb-desktop:~/testlink$ ls -l
total 0
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 a -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 b -> c
pjb@pjb-desktop:~/testlink$ echo foo > c
pjb@pjb-desktop:~/testlink$ cat a
foo
pjb@pjb-desktop:~/testlink$ readlink -e a
/home/pjb/testlink/c
注意:readlink a 本身返回 b
注意 #2:与 find -l 一起使用,可以很容易地用 perl 编写一个列出链的实用程序,但也必须足够智能以检测循环
如果有循环,readlink 将不会输出任何内容。我想,这比卡住要好。
pjb@pjb-desktop:~/testlink$ ln -sf a c
pjb@pjb-desktop:~/testlink$ ls -l
total 0
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 a -> b
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 08:48 b -> c
lrwxrwxrwx 1 pjb pjb 1 2010-02-23 09:03 c -> a
pjb@pjb-desktop:~/testlink$ readlink -e a
pjb@pjb-desktop:~/testlink$ # (note: no output)
答案3
以下是 Bash 中的递归函数:
chain() { export chain; local link target; if [[ -z $chain ]]; then chain="$1"; fi; link=$(stat --printf=%N $1); while [[ $link =~ \-\> ]]; do target="${link##*\`}"; target="${target%\'}"; chain+=" -> $target"; chain "$target"; return; done; echo "$chain"; unset chain; }
多行:
chain() {
export chain
local link target
if [[ -z $chain ]]
then
chain="$1"
fi
link=$(stat --printf=%N "$1")
while [[ $link =~ \-\> ]]
do
target="${link##*\`}"
target="${target%\'}"
chain+=" -> $target"
if [[ ! $target =~ / && $1 =~ / ]]
then
target="${1%/*}/$target"
fi
chain "$target"
return
done
echo "$chain"
unset chain
}
例子:
$ chain d
d -> c -> b -> a
$ chain c
c -> b -> a
$ chain a
a
它所需要的stat(1)
某些系统可能不存在。
如果名称包含反引号、单引号或“->”,它将失败。它会陷入带有符号链接循环的循环中(这可以使用 Bash 4 中的关联数组来解决)。它会导出一个名为“chain”的变量,而不管它是否已在使用中。
它可能还存在其他问题。
编辑:
修复了一些相对符号链接的问题。有些仍然不起作用,但以下版本不需要链接的目标存在。
添加了使用 readlink 的版本:
chain ()
{
export chain;
local target;
if [[ -z $chain ]]; then
chain="$1";
fi;
target=$(readlink "$1");
while [[ $target ]]; do
chain+=" -> $target";
if [[ ! $target =~ / && $1 =~ / ]]
then
target="${1%/*}/$target"
fi
chain "$target";
return;
done;
echo "$chain";
unset chain
}
答案4
awk
您可以使用类似或的方法对 namei 的输出进行后处理,grep
以获得您想要的行:
namei d | awk '$1=="l"'
或者
namei d | egrep -e "->"