如何获得“ realpath”以找到我的符号链接?


13

我使用MacOSX bash作为外壳。我有这样创建的符号链接:

ln -s /usr/bin/python python2 

我有一个使用python2的软件包,我想在我当前的工作目录中创建一个/usr/bin/python实际上是python2 的符号链接。当我python2从命令行执行a时,出现此错误:

python2: realpath couldn't resolve "/usr/bin/python2"

但是像这样调用它./python2可以正确解析路径。我PATH.。实际上,为了进行测试,我将其修改为仅包含.在其中。

我该如何解决?谢谢!


语境

以下建议的解决方案对我不起作用。我试图提炼出尽可能集中和简短的问题,以使人们不会淹没在文字的海洋中,但是显然我需要提供更多的背景知识。

我正在尝试从git克隆的软件包上进行开发。原始软件包,git-multimail是/是在Linux的某些变体上开发的(我猜是Ubuntu)。我一直在尝试对其进行修改,以使其能够在MacOSX上使用它及其测试套件,而只需进行尽可能少的修改。这就是一些建议的解决方案不理想的原因:

  1. 以root python2身份在/ usr / bin /中创建一个符号链接。我正在寻找不需要此解决方案的解决方案。在一开始,这是一个显而易见的选择,但是我想要一个尽可能少地修改主机系统的解决方案。这就是为什么我想在当前工作目录中创建一个临时符号链接,将CWD(即.)添加到我的路径,然后在完成时销毁它(即符号链接)。

  2. 创建包装器脚本以使用现有python调用python脚本。问题在于,大多数测试套件都将实际的script_files用作可执行文件,具体取决于shebang来找到正确的执行环境。这将意味着大量编辑测试套件。在这种情况下(有关测试框架的摘要,请参见下文),我将不得不为每个.py文件添加一个包装器;进一步,用户/开发人员将必须了解使用软件包的不同规则,具体取决于它们所在的系统(即,在MacOSX上,请确保在不通过包装或显式调用python文件的情况下,不要使用python文件/usr/bin/python file.py)。

    #! /bin/sh
    
    D=$(cd $(dirname "$0") && pwd)
    MULTIMAIL="$D/../git-multimail/git_multimail.py"
    POST_RECEIVE="$D/../git-multimail/post-receive"
    
    TESTREPO=$("$D/create-test-repo")
    
    HOME="$D"
    XDG_CONFIG_HOME="$D"
    GIT_CONFIG_NOSYSTEM=1
    export HOME XDG_CONFIG_HOME GIT_CONFIG_NOSYSTEM
    
    cd $TESTREPO
    
    test_email() {
        REFNAME="$1"
        OLDREV="$2"
        NEWREV="$3"
        echo "$OLDREV" "$NEWREV" "$REFNAME" | USER=pushuser "$MULTIMAIL"
    
    } 
  3. 将所有python2引用更改为python自述文件建议了这一点,但这有效地使版本控制无用,因为系统将更改视为新版本,而实际上却并非如此。

我一直在使用(3),但我正在尝试寻找更好的解决方案。我愿意接受这只是事物的本质(即没有合适的方法可以将“ python2”指向/usr/bin/python可移植且不引人注意的方法,而无需对测试套件和实际框架进行大量更改)。


1
嘿! Justln -s /usr/bin/python /usr/bin/python2
nedil 2014年

实际上,我在Linux上开发了git-multimail。但是我欢迎补丁程序和测试器使其在OS X上运行。顺便说一句,由于git-multimail接受python2和python3 :-),您的“ python2”问题现在已解决。
Matthieu Moy

扩展后的问题仍然缺少一个关键的细节:可执行脚本中的shebang行是什么样的?因为git-multimail.py#!/usr/bin/env python2,所以有一种(相对)简单的方法可以做到这一点。
亚历克西斯

@enedil的评论没有用,但是起作用ln -s /usr/bin/python2.7 /usr/local/bin/python2
Phylliida

Answers:


3

如果您需要解析(或研究)符号链接,则可以使用平台无关的bash库“ realpath-lib”。默认情况下,它模拟readlink,并且可以在Mac或Unix上运行。它可以在GithubBitbucket上找到,并且是免费的。

但是听起来您只想从本地(工作)目录中执行python2(而不是./python2)。可能可以使用.bashrc中的别名来执行此操作,否则您将需要将工作目录(包含符号链接)添加到PATH环境变量中。也可以仅在当前会话中完成此操作,也可以在.bashrc文件中完成此操作以用于将来的会话。这可能只是针对特定用户的解决方案。

适用于所有用户的另一个选项是在路径上的另一个目录(例如/ usr / local / bin)中创建到/ usr / bin / python的python2符号链接。也许像这样:

sudo ln -s /usr/bin/python /usr/local/bin/python2

然后,任何用户或脚本都应该找到python或python2命令。当然,此选项需要管理员(root)特权才能安装。


我最终放弃了。在代码中假设'python2'的地方太多了,并不是每个本地化的解决方案都涵盖了所有可能性。这是最适合此指甲的大锤。
艾利·陈

@Avery,您尝试过我的解决方案吗?有问题吗?它不会要求你添加python2/usr/bin(虽然我认为将其作为一种改进,说实话)。
亚历克西斯

可能可以使用别名(...)来完成此操作。这是不可能的,因为别名只会影响命令行,而不会影响脚本。请参阅如何在Debian 7.5中更改Python的默认版本?
Piotr Dobrogost 2014年

这不是正确的答案,至少它不能解决提示张贴者提出问题的问题。
smaudet

16

我相信您在使用Apple的系统来管理同一程序的多个版本之间进行切换。您可以使用以下脚本来轻松完成所需的工作,但不会出现问题python2

#!/bin/bash
exec /usr/bin/python "$@"

将其设为可执行(chmod +x python2),就可以开展业务。

问题说明:

运行时/usr/bin/python,它将python2.7 在同一目录中查找并执行您的符号链接失败,因为系统将符号链接跟随到/usr/bin,然后 python2此处找到找不到。通过使用“硬链接”而不是符号链接,您可以更进一步:

rm python2
ln /usr/bin/python python2

现在没有符号链接可跟,只有同一个文件(inode)的两个文件名。但是现在我失败了,并显示以下消息:

python2: posix_spawn: /Users/alexis/.../python22.7: No such file or directory

请注意python22.7:框架正在添加2.7您创建的名称!我建议您不要使用版本管理框架,而应使用上面建议的解决方案而不是试图解开它并建立一个符合其期望的链接林。

PS。可能会有更好的解决方案:如果您先解释一下需要做的事情(为什么要提供python2的别名python),那么有人可能会以不同的方式帮助您。这在stackexchange语言中被称为“ XY问题”。


运行时/usr/bin/python,它将在同一目录中找到并执行python2.7。这是非常令人困惑的声明。如果您描述/usr/bin/python符号链接的情况,请更具体。
Piotr Dobrogost 2014年

那真是太糟糕了..
nicolas 2015年

有什么惊人的坏处?
Alexis 2015年

是的,这里没有明确提到的是,我认为/ usr / bin / python实际上不是python,它只是查找MacOS安装的python(与框架文件夹符号链接的python2.7)。我怀疑@nicolas是说伪造的python版本太糟糕了-这确实是黑客,我希望Apple没有这样做。...我有很多希望苹果不做的事情,只是夸耀了他们本来不错的Unix系统。
smaudet

3

尝试:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2

1
不知道您为什么会投票反对,这是唯一对我
有用的

1

您可以使用Unix命令readlink找出链接的物理路径。

例子

说我有以下链接:

$ ls -l /usr/bin/etags
lrwxrwxrwx. 1 root root 29 Dec 10 22:56 /usr/bin/etags -> /etc/alternatives/emacs.etags

$ ls -l /etc/alternatives/emacs.etags
lrwxrwxrwx. 1 root root 20 Dec 10 22:56 /etc/alternatives/emacs.etags -> /usr/bin/etags.ctags

$ ls -l /usr/bin/etags.ctags
lrwxrwxrwx. 1 root root 5 Dec 10 22:56 /usr/bin/etags.ctags -> ctags

  1. 要查找符号链接指向的值

    $ readlink /usr/bin/etags
    /etc/alternatives/emacs.etags

    注意:以上结果可能是另一个链接。要解决此问题,请参见下面的#2。

  2. 为了找出符号链接指向的值的绝对路径

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags

0

我不明白-您认为包装器链接没问题,但包装器脚本不行吗?任一只是间接级别。而且,您是否还不必指示用户仅从某个目录调用它?

无论如何,您当然可以获取当前的工作目录$PATH

 echo "echo \"Hi! I'm python\"" >|./python 
 chmod +x ./python 
 PATH="${PWD}:${PATH}" 
 python

 #OUTPUT#
 Hi! I'm python

 rm python 
 python -V 
 ln -s /usr/bin/python2 ./python 
 python -V

 #OUTPUT#
 Python 3.4.0
 Python 2.7.6

 PATH="${PATH#"${PWD}:"}" 
 python -V

 #OUTPUT#
 Python 3.4.0

请得到。从你的$PATH。这是一个可怕的想法。


为什么.在我的$ PATH中有一个坏主意?如果我把它放在最后,那么最后一个要看的地方就是我当前的工作目录(即PATH =“ $ {PATH}:$ {PWD}”。包装脚本意味着对于每个python文件,我都会必须创建一个附加文件。python可执行文件的包装器链接只是为我创建了一件事情
Avery Chan

@AveryChan我不这么认为。包装脚本可以提供与可执行文件同名的shell函数或别名。它也可以--bind mount在当前目录或(chroot必要时,我猜只是Linux)中执行。但是。在$PATH对作品的任何目录,不具体。这对您的用户是危险的。无论如何,我在上面非常清楚地演示了如何做到这一点。它不符合您的要求吗?
mikeserv

0

回复@alexis答案,其中的python版本/usr/bin不是真正的python。

这应该以三种方式体现出来:

  1. 我们得到的错误不是python通常产生的错误。python的行为不是寻找另一个python,而是执行python脚本。

  2. 如果您计算的阴影/usr/bin/python和实际运行的python2.7:

shasum /usr/bin/python
3782d9ab14b35037c9c7fb665439a5fa695c54a6  /usr/bin/python
shasum /usr/bin/python2.7
476fa96c80ac26a85b2d3b01ddfd19e513660c2c  /usr/bin/python2.7

他们是完全不同的。此外,文件大小相差约20k字节:

ll /usr/bin/python
-rwxr-xr-x  1 root  wheel  66880 May 17  2019 /usr/bin/python

ll /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
-rwxr-xr-x  1 root  wheel  43104 May 17  2019 /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
  1. 最后,您可以反编译python2.7和python并研究符号。不过,这超出了“如何在osx上将python2.7符号链接到python2”的范围。

因此(如错误所示)/usr/bin/python转过身来寻找/usr/bin/python2.7

ll /usr/bin/python2.7
lrwxr-xr-x  1 root  wheel  75 Jul  1  2019 /usr/bin/python2.7 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

这就是为什么以下工作有效的原因(由@ liangmin-li给出答案):

    ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2

欢迎来到该网站。您可能需要添加一些关于如何从示例ls输出中看到/usr/bin/python“不是真正的python”的解释。
AdminBee

这一点显而易见,但是我可以更新确定方式。
smaudet

它可能适合那些知道典型python解释器二进制文件大小的人,但是请记住,这里的答案应该对更一般的U&L读者
有用

1
我已经更新了样本。但是,证明二进制身份是一个困难的问题,这就是为什么我在这里没有完全解决(大小在版本之间可以合理地不同,行为可以改变的原因-我在更新后的答案中发表的证据是该系统的行为与方式我应该认为关于反向工程python二进制的答案不是合适的,或者在这里真的没有帮助)。但是我理解你的意思。
smaudet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.