111

I want to scp a file to a server. The file is a symbolic link, and actually what I want to do is copy the source file.

I don't want to track the source file's path manually, because it can be replaced.

How do I get the source file's absolute path so that I can then scp with it?

  • 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
143

Try this line:

readlink -f `which command`

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

| improve this answer | |
  • 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
  • 13
    -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
  • On my systems, which command outputs which: no command in (…) or nothing.  How does it make sense to use which here?  What am I missing? – G-Man Says 'Reinstate Monica' Jul 28 at 21:00
26

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.

| improve this answer | |
  • 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

| improve this answer | |
6

Stat will give you this information:

$ stat current
  File: `current' -> `/home/user/releases/build/'
  ...
| improve this answer | |
  • 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`" 
| improve this answer | |
  • 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

| improve this answer | |
  • 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)
| improve this answer | |
  • 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
| improve this answer | |
0

The following would give the full path resolving the symlink.

which [symlink] | xargs realpath
| improve this answer | |

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.