如何列出符号链接链中的所有成员?
如何列出符号链接链中的所有成员?
找到Java二进制文件可能会很麻烦:
which java
返回/usr/bin/java
lh $(which java)
返回/usr/bin/java -> /etc/alternatives/java
lh /etc/alternatives/java
返回/etc/alternatives/java -> /usr/lib/jvm/jdk1.8.0_66/bin/java
有没有一种自动跟随符号链接链并打印所有成员的方法?例如 whichfollow
或 follow /usr/bin/java
可以返回:
/usr/bin/java -> /etc/alternatives/java -> /usr/lib/jvm/jdk1.8.0_66/bin/java
如何列出符号链接链中的所有成员?
在GNU/Linux中,除了使用readlink
命令外,用户还可以使用来自util-linux包的namei
命令。根据其手册页面:
namei使用其参数作为Unix文件(符号链接、文件、目录等)的路径名。然后,namei会跟随每个路径名,直到找到一个终点(文件、目录、设备节点等)。如果它找到一个符号链接,它会显示该链接,并开始跟随它,缩进输出以显示上下文。
它的输出不像你希望的那样美观,但它显示了每个路径组件,并显示它是目录、符号链接、套接字、块设备、字符设备、FIFO(命名管道)还是普通文件。
示例用法:
$ namei /usr/bin/java f: /usr/bin/java d / d usr d bin l java -> /etc/alternatives/java d / d etc d alternatives l java -> /usr/lib/jvm/jre-1.7.0-openjdk/bin/java d / d usr d lib d jvm l jre-1.7.0-openjdk -> java-1.7.0-openjdk-1.7.0.85/jre d java-1.7.0-openjdk-1.7.0.85 d jre d bin - java
很棒的东西;看起来namei
在许多发行版上都预装了,并且可以列出其他信息,例如模式位。我希望它能解析相对目标路径为绝对路径;如果没有它,有时很难确定指的是哪个路径,特别是带有..
组件的情况。
如何列出符号链接链中的所有成员?
有时候我们可能需要查看一个符号链接链中的所有成员,以了解符号链接是如何链接到最终目标的。下面是几种解决这个问题的方法:
1. 使用typex工具:typex是一个使用绝对路径打印给定路径的符号链接链的工具。它可以通过以下命令进行安装:
npm install typex -g
使用示例:
$ typex awk BINARY: /usr/bin/awk@ -> /etc/alternatives/awk@ -> /usr/bin/gawk [GNU Awk 4.0.1]
2. 使用rreadlink工具:rreadlink是一个更底层的工具,可以打印任何给定文件系统路径的符号链接链。它可以通过以下命令进行安装:
npm install rreadlink -g
使用示例:
$ rreadlink -1 "$(which awk)" /usr/bin/awk /etc/alternatives/awk /usr/bin/gawk
3. 使用rreadlinkchain函数:rreadlinkchain是一个完全符合POSIX标准的脚本/函数,只使用POSIX shell语言特性和符合POSIX标准的工具调用。它可以递归地打印符号链接链的每一步的绝对路径,直到最终目标。以下是rreadlinkchain函数的代码:
#!/bin/sh ## ------- # SYNOPSIS # rreadlinkchain <symLink> # DESCRIPTION # Recursive readlink: prints the CHAIN OF SYMLINKS from the input # file to its ultimate target, as ABSOLUTE paths, with each path on a separate # line. # Only the ultimate target's path is canonical, though. # A broken symlink in the chain causes an error that reports the # non-existent target. # An input path that is not a symlink will print its own canonical path. # LIMITATIONS # - Won't work with filenames with embedded newlines or filenames containing # the string ' -> '. # COMPATIBILITY # Fully POSIX-compliant. # EXAMPLES # # Print the symlink chain of the `git` executable in the $PATH. # rreadlinkchain "$(which git)" # # Ditto, using single-line `ls -l`-style format ('a@ -> b') # rreadlinkchain "$(which git)" | sed -nE -e '$!{a\'$'\n''@ -> ' -e '}; p' | tr -d '\n' # THANKS # https://stackoverflow.com/a/1116890/45375 rreadlinkchain() ( # execute in *subshell* to localize the effect of `cd`, ... target=$1 targetDir= targetName= CDPATH= # Try to make the execution environment as predictable as possible: # All commands below are invoked via `command`, so we must make sure that # `command` itself is not redefined as an alias or shell function. # (Note that command is too inconsistent across shells, so we don't use it.) # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not # even have an external utility version of it (e.g, Ubuntu). # `command` bypasses aliases and shell functions and also finds builtins # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for # that to happen. { \unalias command; \unset -f command; } >/dev/null 2>&1 [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too. while :; do # Unless the file is a symlink OR exists, we report an error - note that using `-e` with a symlink reports the *target*'s existence, not the symlink's. [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." 1>&2; return 1; } # !! We use `cd` to change to the target's folder # !! so we can correctly resolve the full dir. path. command cd "$(command dirname -- "$target")" # note: cd "" is the same as cd . - i.e., a no-op. targetDir=$PWD targetName=$(command basename -- "$target") [ "$targetName" = '/' ] && targetName='' # !! curiously, `basename /` returns '/' done=0 if [ ! -L "$targetName" ]; then # We've found the ultimate target (or the input file wasn't a symlink to begin with). # For the *ultimate* target we want use `pwd -P` to make sure we use the actual, physical directory, # (not a symlink) to get the *canonical* path. targetDir=$(command pwd -P) done=1 fi # Print (next) path - note that we manually resolve paths ending # in /. and /.. to make sure we have a normalized path. if [ "$targetName" = '.' ]; then command printf '%s\n' "${targetDir%/}" elif [ "$targetName" = '..' ]; then # Caveat: something like /var/.. will resolve to /private (assuming # /var@ -> /private/var), i.e. the '..' is applied AFTER canonicalization. command printf '%s\n' "$(command dirname -- "${targetDir}")" else command printf '%s\n' "${targetDir%/}/$targetName" fi # Exit, if we've hit the non-symlink at the end of the chain. [ "$done" = 1 ] && break # File is symlink -> continue to resolve. # Parse `ls -l` output, which, unfortunately, is the only POSIX-compliant # way to determine a symlink's target. Hypothetically, this can break with # filenames containig literal ' -> ' and embedded newlines. target=$(command ls -l -- "$targetName") target=${target#* -> } done ) rreadlinkchain "$@"
这些方法都可以在多个平台上使用,并提供了对符号链接链的详细输出。
如何列出符号链接链中的所有成员?
考虑安装“chase”:
示例输出:
$ chase --verbose /usr/bin/java
/usr/bin/java
-> /etc/alternatives/java
-> /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java
/usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java
软件包描述:
包:chase
状态:已安装
自动安装:否
版本:0.5.2-4build2
优先级:可选项
部分:universe/utils
维护者:Ubuntu Developers
构架:amd64
未压缩大小:61.4 k
依赖项:libc6(>= 2.3.4),libgc1c2(>= 1:7.2d)
冲突:chase
描述:跟踪符号链接并打印其目标文件
Chase是一个用于追踪符号链接指向的实际文件的小型实用程序-追踪符号链接。成功运行的结果保证是一个存在的文件,而不是一个符号链接。
好好知道,也很高兴看到“chase”具有符号链接循环检测。与“namei”不同,“chase”令人称赞地始终将最终的目标路径作为绝对路径打印出来,但我希望它也能对中间的路径进行同样的操作,这些路径的目标被定义为相对路径(可能还包括相对路径),因为并不总是明显指的是哪个路径,特别是使用“..”。