Linux:查找给定“原始”文件的所有符号链接? (反向'readlink')

时间:2010-12-26 00:04:48

标签: linux bash symlink reverse

考虑以下命令行代码:

$ cd /tmp/
$ mkdir dirA
$ mkdir dirB
$ echo "the contents of the 'original' file" > orig.file
$ ls -la orig.file 
-rw-r--r-- 1 $USER $USER 36 2010-12-26 00:57 orig.file

# create symlinks in dirA and dirB that point to /tmp/orig.file:

$ ln -s $(pwd)/orig.file $(pwd)/dirA/
$ ln -s $(pwd)/orig.file $(pwd)/dirB/lorig.file
$ ls -la dirA/ dirB/
dirA/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:57 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:57 orig.file -> /tmp/orig.file

dirB/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:58 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:58 lorig.file -> /tmp/orig.file

此时,我可以使用readlink来查看“原始”是什么(好吧,我想这里通常的术语是“目标”或“来源”,但我脑海中的那些可能相反概念也是如此,所以我只称它为符号链接的“原始”文件,即

$ readlink -f dirA/orig.file 
/tmp/orig.file
$ readlink -f dirB/lorig.file 
/tmp/orig.file

...但是,我想知道的是 - 是否有一个命令我可以在'原始'文件上运行,并找到指向它的所有符号链接?换句话说,像(伪):

$ getsymlinks /tmp/orig.file
/tmp/dirA/orig.file 
/tmp/dirB/lorig.file

提前感谢任何评论,

干杯!

5 个答案:

答案 0 :(得分:129)

使用GNU find,这将找到硬链接或符号链接到文件的文件:

find -L /dir/to/start -samefile /tmp/orig.file

答案 1 :(得分:30)

我没有看到这样的命令,这不是一件容易的事,因为目标文件包含关于源文件指向它的零信息。

这类似于“硬”链接,但至少这些链接始终位于同一文件系统中,因此您可以find -inode列出它们。软链接更有问题,因为它们可以跨文件系统。

我认为您要做的事情基本上是对整个层次结构中的每个文件执行ls -al,并使用grep搜索-> /path/to/target/file

例如,这是我在我的系统上运行的一个(格式化为可读性 - 最后两行实际上是在实际输出中的一个行):

pax$ find / -exec ls -ald {} ';' 2>/dev/null | grep '\-> /usr/share/applications'
lrwxrwxrwx 1 pax pax 23 2010-06-12 14:56 /home/pax/applications_usr_share
                                         -> /usr/share/applications

答案 2 :(得分:2)

符号链接不会跟踪指向给定目标的内容,因此您无法检查每个符号链接以查看它是否指向所需目标,例如

for i in *; do
    if [ -L "$i" ] && [ "$i" -ef /tmp/orig.file ]; then
        printf "Found: %s\n" "$i"
    fi
done

答案 3 :(得分:0)

这就是我想出的。我在OS X上执行此操作,它没有readlink -f,所以我不得不使用辅助函数来替换它。如果你有一个合适的readlink -f,你可以使用它。此外,在这种情况下,并不严格需要使用while ... done < <(find ...),简单的find ... | while ... done可以使用;但是如果你想做一些事情,比如在循环中设置变量(比如匹配文件的数量),管道版本就会失败,因为while循环会在子shell中运行。最后,请注意我使用find ... -type l,因此循环只在符号链接上执行,而不是在其他类型的文件上执行。

# Helper function 'cause my system doesn't have readlink -f
readlink-f() {
    orig_dir="$(pwd)"
    f="$1"
    while [[ -L "$f" ]]; do
        cd "$(dirname "$f")"
        f="$(readlink "$(basename "$f")")"
    done
    cd "$(dirname "$f")"
    printf "%s\n" "$(pwd)/$(basename "$f")"
    cd "$orig_dir"
}

target_file="$(readlink-f "$target_file")" # make sure target is normalized

while IFS= read -d '' linkfile; do
    if [[ "$(readlink-f "$linkfile")" == "$target_file" ]]; then 
        printf "%s\n" "$linkfile"
    fi
done < <(find "$search_dir" -type l -print0)

答案 4 :(得分:0)

受到Gordon Davisson的评论启发。这与另一个答案类似,但我使用exec获得了预期的结果。我需要能找到符号链接而不知道原始文件位于何处的东西。

find / -type l -exec ls -al {} \; | grep -i "all_or_part_of_original_name"