99

I want to scp a file to a server. The file is a symbolic link, and actually what I want to do is copying the source file. Anyway I don't want to track source file's path manually, because it can be replaced. If I can get source file's absolute path, I can sep with it. How can I get the path?

  • 2
    Most scp versions follow symlinks by default, don't they? You should check yours and maybe save yourself some work. – jw013 Oct 6 '11 at 3:26
  • @jw103 Thanks for letting me know it. I didn't know. :) – Eonil Oct 6 '11 at 4:42
  • 2
    Note: scp -r forces following symlinks. – Eonil Oct 6 '11 at 4:43
129

Try this line:

readlink -f `which command`

If command is in your $PATH variable , otherwise you need to specify the path you know.

  • 12
    -f will return a path to a non-existent final target, so long as the intermediate link targets exist... Use -e to avoid this, ie. -e will return null if the final target does not exist. – Peter.O Oct 6 '11 at 4:31
  • 10
    -f errored with readlink: illegal option -- f in OSX. Removing it worked fine. – Heath Borders Nov 13 '13 at 16:44
  • 2
    @HeathBorders For OSX if you have homebrew coreutils installed you can also use greadlink instead. – Adam Gent Aug 22 '16 at 14:47
23

Under Linux, readlink reads the contents of a symlink, and readlink -f follows symlinks to symlinks to symlinks, etc., until it finds something that isn't a symlink.

This isn't necessary for scp though: scp always follows symlinks (it always copies file content, ignoring metadata except that -p preserves file times and modes when possible).

If you find yourself disappointed by what metadata scp can and can't preserve, I suggest using rsync. With no option, rsync copies file contents ignoring metadata. The commonly used option -a preserves all garden-variety metadata (times, symbolic links, permissions and ownership), and there are options to preserve exotic metadata like ACLs and hard links.

  • readlink do only single step for read linking. for example in ubuntu we have /bin/zsh , that is symlinked to /etc/alternatives/zsh , but this is second symlink. Finally we will not get real file or directory path. The same is with stat command. Only readlink with -f option do all resolves. – Znik Mar 23 '18 at 9:52
9

I use command ls, stat, readlink.

Take file /etc/localtime as an example

[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

Operation

Using stat

[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’

Using readlink

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

It seems like that command readlink -f is better.

Explanation

-f, --canonicalize: canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist —— From man readlink

6

Stat will give you this information:

$ stat current
  File: `current' -> `/home/user/releases/build/'
  ...
  • readlink do only single step for read linking. for example in ubuntu we have /bin/zsh , that is symlinked to /etc/alternatives/zsh , but this is second symlink. Finally we will not get real file or directory path. The same is with stat command. Only readlink with -f option do all resolves. – Znik Mar 23 '18 at 9:53
5

You can either do

readlink -f `which command`

or you can get something similar in Linux with

stat `which command` | grep File

If you are adding this to a script, inspect the error. If you don't want to see the error message in the case when the sym link is not there, go with something like

readlink -f "`which command`" 
  • stat and realink without -f do only single step. then better call readlink -f . – Znik Mar 23 '18 at 9:56
3

I would use realpath <symlink>.

Probably what you call 'source' is the 'target' file according to the usage of ln: Usage: ln [OPTION]... [-T] TARGET LINK_NAME

  • Thanks This worked like a charm! with Mac OSX! where readlink didn't cut it...stupid mac. lol – JayRizzo Aug 20 '18 at 6:48
0

readlink -f 'which java' didn't work for me.

But this did:

readlink -f $(which java)
  • 3
    Didn't work because it is ` not '.. but $() is better practice anyways. – Stephen Rauch Jun 27 '17 at 18:15
  • Why downvote? My answer is an acceptable alternative, and, as the comment says, a better practice. – NonCreature0714 Nov 10 '17 at 16:32
  • 1
    Most people who down vote do not also comment, so asking for an explanation of a down vote will rarely get you an explanation, because the down voter has already left and isn't likely to come back. I would suggest you remove the typoed code that does not work from your answer. I would be willing to up vote if you took the time to clean it up and explain why $() is better practice. – Stephen Rauch Nov 10 '17 at 16:38
  • As Stephen explained to you, ' is not ` . You should encapsulate by command , but this is deprecated. using $() is better, because encapsulation $( $(command) ) is much easier and don't need special escaping. Then it is preferred. In your first example you used usual apostrophe, then readlink is trying to find file named 'which java' with space in its name. But you intention is call command which with argument java, for finding java binary executable path. – Znik Mar 23 '18 at 10:02
0

On MAC OX, "-f" parameter doesn't work, 'readlink' works without any parameter.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.