如何获得软符号链接的原始文件的完整路径?


99

我想将scp文件发送到服务器。该文件是一个符号链接,实际上我要复制源文件。无论如何,我不想手动跟踪源文件的路径,因为可以替换它。如果可以获取源文件的绝对路径,则可以sep使用它。我怎么走?


2
大多数scp版本默认都遵循符号链接,不是吗?您应该检查一下,也许可以节省一些工作。
jw013 2011年

@ jw103感谢您让我知道。我不知道 :)
Eonil 2011年

2
注意:scp -r强制遵循符号链接。
Eonil,2011年

Answers:


129

试试这一行:

readlink -f `which command`

如果command在您的$PATH变量中,否则您需要指定您知道的路径。


12
-f只要中间链接目标存在,它将返回一个不存在的最终目标的路径-e-e如果最终目标不存在,则将返回null。
2011年

10
-freadlink: illegal option -- f在OSX中出现错误。删除它工作正常。
Heath Borders

2
@HeathBorders对于OSX,如果您安装了自制的coreutils,则也可以使用greadlink
亚当·根特

23

在Linux下,readlink读取符号链接的内容,并readlink -f跟随符号链接到符号链接到符号链接等,直到找到不是符号链接的内容。

但是,这对于scp而言不是必需的:scp始终遵循符号链接(它始终复制文件内容,忽略元数据,但-p在可能的情况下会保留文件时间和模式)。

如果您对元数据scp可以保留和不能保留的内容感到失望,建议您使用rsync。如果没有选择,rsync将忽略元数据复制文件内容。常用的选项-a保留所有花园类型的元数据(时间,符号链接,权限和所有权),还有一些选项可保留异类元数据,例如ACL和硬链接。


readlink仅执行单步进行读取链接。例如在ubuntu中,我们有/ bin / zsh,它与/ etc / alternatives / zsh符号链接,但这是第二个符号链接。最后,我们将不会获得真实的文件或目录路径。stat命令也是如此。只有带有-f选项的readlink才能解决所有问题。
Znik

9

我使用的命令lsstatreadlink

以文件/etc/localtime为例

[flying@lempstacker ~]$ ls /etc/localtime 
/etc/localtime
[flying@lempstacker ~]$ ls -l /etc/localtime
lrwxrwxrwx. 1 root root 35 Aug  2 22:41 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai

运作方式

使用统计

[flying@lempstacker ~]$ stat /etc/localtime
  File: ‘/etc/localtime’ -> ‘../usr/share/zoneinfo/Asia/Shanghai’
  Size: 35          Blocks: 0          IO Block: 4096   symbolic link
Device: fd01h/64769d    Inode: 272202388   Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2016-11-23 09:00:59.999887800 +0800
Modify: 2016-08-02 22:41:26.090389904 +0800
Change: 2016-08-02 22:41:26.090389904 +0800
 Birth: -
[flying@lempstacker ~]$ stat -c "%N" /etc/localtime
‘/etc/localtime’ -> ‘../usr/share/zoneinfo/Asia/Shanghai’

使用readlink

[flying@lempstacker ~]$ readlink /etc/localtime
../usr/share/zoneinfo/Asia/Shanghai
[flying@lempstacker ~]$ readlink -f /etc/localtime
/usr/share/zoneinfo/Asia/Shanghai

似乎该命令readlink -f更好。

说明

-f,--canonicalize:通过递归跟随给定名称的每个组件中的每个符号链接来规范化;除了最后一个组件之外的所有组件都必须存在-从man readlink


6

Stat将为您提供以下信息:

$ stat current
  File: `current' -> `/home/user/releases/build/'
  ...

readlink仅执行单步进行读取链接。例如在ubuntu中,我们有/ bin / zsh,它与/ etc / alternatives / zsh符号链接,但这是第二个符号链接。最后,我们将不会获得真实的文件或目录路径。stat命令也是如此。只有带有-f选项的readlink才能解决所有问题。
Znik

5

你可以做

readlink -f `which command`

或者您可以在Linux中使用

stat `which command` | grep File

如果要将其添加到脚本中,请检查错误。如果在符号链接不存在的情况下不想看到错误消息,请使用类似

readlink -f "`which command`" 

不带-f的stat和realink仅执行单个步骤。然后最好调用readlink -f。
Znik

3

我会用realpath <symlink>

根据以下用途,您所谓的“源”可能是“目标”文件lnUsage: ln [OPTION]... [-T] TARGET LINK_NAME


谢谢这就像一个魅力!使用Mac OSX!哪里readlink没有剪掉...愚蠢的mac。大声笑
JayRizzo 18'Aug

0

readlink -f 'which java' 没有为我工作。

但是这样做:

readlink -f $(which java)

3
没用是因为它`不是'..但$()还是更好的做法。
Stephen Rauch

为什么要投票?我的答案是可以接受的替代方法,并且如评论所述,这是一种更好的做法。
NonCreature0714

1
大多数投下反对票的人也不会发表评论,因此,要求对投下反对票的原因进行解释的人很少,因为投下反对票的人已经离开并且不太可能回来。我建议您从答案中删除无效的键入代码。如果您花时间清理它并解释为什么$()更好的做法,我将愿意投票。
Stephen Rauch

正如史蒂芬(Stephen)向您解释的那样,“不是”。您应该使用封装command,但已弃用。使用$()更好,因为封装$($(command))更容易,并且不需要特殊的转义。然后是首选。在您的第一个示例中,您使用了通常的撇号,然后readlink尝试查找名称为'哪个java'且名称中带有空格的文件。但是您打算使用带有参数java的call命令,以查找java二进制可执行路径。
Znik

0

在MAC OX上,“-f”参数无效,“ readlink”在没有任何参数的情况下有效。

KZs-MacBook-Pro:bin kz$ readlink -f pip3
readlink: illegal option -- f
usage: readlink [-n] [file ...]

KZs-MacBook-Pro:bin kz$ readlink pip3
../../../Library/Frameworks/Python.framework/Versions/3.7/bin/pip3
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.