当前位置:  开发笔记 > 编程语言 > 正文

如何解析shell脚本中的符号链接

如何解决《如何解析shell脚本中的符号链接》经验,为你挑选了7个好方法。

给定绝对或相对路径(在类Unix系统中),我想在解析任何中间符号链接后确定目标的完整路径.奖励积分也可以同时解析〜用户名表示法.

如果目标是目录,则可以将chdir()放入目录然后调用getcwd(),但我真的想从shell脚本而不是编写C帮助程序.不幸的是,shell倾向于试图隐藏用户的符号链接(这是OS X上的bash):

$ ls -ld foo bar
drwxr-xr-x   2 greg  greg  68 Aug 11 22:36 bar
lrwxr-xr-x   1 greg  greg   3 Aug 11 22:36 foo -> bar
$ cd foo
$ pwd
/Users/greg/tmp/foo
$

我想要的是一个函数resolve(),这样当从上例中的tmp目录执行时,解析("foo")=="/ Users/greg/tmp/bar".



1> pixelbeat..:
readlink -f "$path"

编者注:以上内容适用于GNU readlinkFreeBSD/PC-BSD/OpenBSD readlink,但从10.11开始不适用于OS X.
GNU readlink提供了其他相关选项,例如,-m无论最终目标是否存在,都可以解析符号链接.

请注意,自GNU coreutils 8.15(2012-01-06)以来,有一个可用的实际路径程序比上面的更简单,更灵活.它还与同名的FreeBSD util兼容.它还包括生成两个文件之间的相对路径的功能.

realpath $path

[管理员在下面评论halloleo - danorton]

对于Mac OS X(通过至少10.11.x),请使用readlink不带-f选项:

readlink $path

编者注:这不会递归地解析符号链接,因此不会报告最终目标; 例如,给定a指向的符号链接指向(仅b指向)c,这只会报告b(并且不会确保它作为绝对路径输出).在OS X上
使用以下perl命令填补缺少的readlink -f功能的空白:
perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"


在OS X上,您可以使用自制软件安装coreutils.它将其安装为"grealpath".
`readlink`适用于OSX,但需要另一种语法:`readlink $ path`*不带*-f`.
这在Mac OS X中不起作用 - 请参阅http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
readlink无法取消引用多个符号链接层,但它一次只能解析一个层

2> kauppi..:

根据标准,pwd -P应该返回解决了符号链接的路径.

C函数char *getcwd(char *buf, size_t size)unistd.h应具有相同的行为.

getcwd pwd


这适用于(当前)目录?如果目标是一个文件,它将不会给出任何东西......
总结一下后见之明的好处:这个答案只适用于非常有限的情况,即如果感兴趣的符号链接是_directory_实际_exists_; 另外,在调用`pwd -P`之前,你必须首先`cd`它.换句话说:它不允许你解析(见目标)符号链接_to files_或_broken_符号链接,并且为了解析现有目录符号链接你必须做额外的工作(恢复以前工作的目录或本地化`cd `和`pwd -P`调用子shell).
如果链接断开,则无效,因为您无法将其作为当前路径

3> tlrobinson..:

如果您只是想要目录,"pwd -P"似乎有效,但如果由于某种原因您想要实际可执行文件的名称,我认为这没有帮助.这是我的解决方案:

#!/bin/bash

# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")

# resolve symlinks
while [[ -h $SELF_PATH ]]; do
    # 1) cd to directory of the symlink
    # 2) cd to the directory of where the symlink points
    # 3) get the pwd
    # 4) append the basename
    DIR=$(dirname -- "$SELF_PATH")
    SYM=$(readlink "$SELF_PATH")
    SELF_PATH=$(cd "$DIR" && cd "$(dirname -- "$SYM")" && pwd)/$(basename -- "$SYM")
done



4> Gregory..:

我最喜欢的一个是 realpath foo

realpath - return the canonicalized absolute pathname

realpath  expands  all  symbolic  links  and resolves references to '/./', '/../' and extra '/' characters in the null terminated string named by path and
       stores the canonicalized absolute pathname in the buffer of size PATH_MAX named by resolved_path.  The resulting path will have no symbolic link, '/./' or
       '/../' components.


realpath现在(2012年1月)是coreutils的一部分,并与debian和BSD变体向后兼容

5> Chuck Kollar..:
readlink -e [filepath]

似乎正是你所要求的 - 它接受一个arbirary路径,解析所有符号链接,并返回"真实"路径 - 它可能是所有系统已经拥有的"标准*nix"



6> Keymon..:

其他方式:

# Gets the real path of a link, following all links
myreadlink() { [ ! -h "$1" ] && echo "$1" || (local link="$(expr "$(command ls -ld -- "$1")" : '.*-> \(.*\)$')"; cd $(dirname $1); myreadlink "$link" | sed "s|^\([^/].*\)\$|$(dirname $1)/\1|"); }

# Returns the absolute path to a command, maybe in $PATH (which) or not. If not found, returns the same
whereis() { echo $1 | sed "s|^\([^/].*/.*\)|$(pwd)/\1|;s|^\([^/]*\)$|$(which -- $1)|;s|^$|$1|"; } 

# Returns the realpath of a called command.
whereis_realpath() { local SCRIPT_PATH=$(whereis $1); myreadlink ${SCRIPT_PATH} | sed "s|^\([^/].*\)\$|$(dirname ${SCRIPT_PATH})/\1|"; } 



7> 小智..:

将一些给定的解决方案放在一起,知道readlink在大多数系统上都可用,但需要不同的参数,这对我在OSX和Debian上运行良好.我不确定BSD系统.也许条件需要仅从OSX中[[ $OSTYPE != darwin* ]]排除-f.

#!/bin/bash
MY_DIR=$( cd $(dirname $(readlink `[[ $OSTYPE == linux* ]] && echo "-f"` $0)) ; pwd -P)
echo "$MY_DIR"

推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有