only show the source file and target linked file using `ls`

11,964

Solution 1

ls unfortunately doesn't have an option to retrieve file attributes and display them in an arbitrary way. Some systems have separate commands for that (for instance GNU has a stat command or the functionality in GNU find).

On most modern systems, with most files, this should work though:

$ ln -s '/foo/bar -> baz' the-file
$ LC_ALL=C ls -ldn the-file | sed '
   1s/^\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{8\}//'
the-file -> /foo/bar -> baz

That works by removing the first 8 blank delimited fields of the first line of the output of ls -l. That should work except on systems where the gid is not displayed there or the first 2 fields are joined together when there's a large number of links.

With GNU stat:

$ LC_ALL=C stat -c '%N' the-file
'the-file' -> '/foo/bar -> baz'

With GNU find:

$ find the-file -prune \( -type l -printf '%p -> %l\n' -o -printf '%p\n' \)
the-file -> /foo/bar -> baz

With FreeBSD/OS/X stat:

f=the-file
if [ -L "$f" ]; then
  stat -f "%N -> %Y" -- "$f"
else
  printf '%s\n' "$f"
fi

With zsh stat:

zmodload zsh/stat
f=the-file
zstat -LH s -- "$f"
printf '%s\n' ${s[link]:-$f}

Many systems also have a readlink command to specifically get the target of a link:

f=the-file
if [ -L "$f" ]; then
  printf '%s -> ' "$f"
  readlink -- "$f"
else
  printf '%s\n' "$f"
fi

Solution 2

Use the file command.

[sreeraj@server ~]$ ls -l mytest
lrwxrwxrwx 1 sreeraj sreeraj 15 Dec 12 09:31 mytest -> /usr/sbin/httpd

[sreeraj@server ~]$ file mytest
mytest: symbolic link to `/usr/sbin/httpd'

or

[sreeraj@server ~]$ file -b mytest
symbolic link to `/usr/sbin/httpd'
[sreeraj@server ~]$

Also, please go read through man page of ls and check the options -L and -H and see if that would suffice your requirement.

Solution 3

With a GNU ls at least (and, apparently, tcsh's implementation) you can hack the $LS_COLORS environment variable to insert delimiters where you like (but tcsh's builtin ls-F doesn't do link targets - only link flags) Usually ls inserts arbitrary non-printable terminal escapes based on the values stored within that environment var, but there's nothing stopping us from inserting arbitrary anything else instead. More on this here.

For example:

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls ~ -l --color=always | 
sed '\|///|,\|//|!d;//d'

That puts a string like // at the head of every listing (so just before lrwcrwx) and a ///\n just before the filename of any link. sed then filters on line ranges - it will delete every input line until it encounters /// and from there through the next line which matches // it will delete lines matching //. So it only gets the link name and link target - regardless of intervening characters. This is because / can't occur in a filename - and those in any path ls might print will only occur singly.

See?

mkdir test; cd test
touch 'long


name' shortname
ln -s l* "$(printf %s.ln l*)"; ln -s s* shortname.ln

LS_COLORS='ln=///\n:lc=:no=//:rc=:rs=:' \
\ls  -l --color=always | sed '\|///|,\|//|!d;//d'

...which prints:

long


name.ln -> long


name
shortname.ln -> shortname

Try it yourself.

Share:
11,964

Related videos on Youtube

Chris Snow
Author by

Chris Snow

Updated on September 18, 2022

Comments

  • Chris Snow
    Chris Snow almost 2 years

    I can show the target file that a link points to using ls -l:

    snowch$ ls -l /usr/local/bin/mvn
    lrwxr-xr-x  1 snowch  admin  29 12 Dec 08:58 /usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn
    

    Is there a way to show less output without having to pipe through another command such as awk? E.g:

    snowch$ ls ?? /usr/local/bin/mvn
    /usr/local/bin/mvn -> ../Cellar/maven/3.2.3/bin/mvn
    

    I'm running 3.2.53 on OS X 10.9.5. The output from several commands is shown below:

    snowch$ ls -H /usr/local/bin/mvn
    /usr/local/bin/mvn
    
    snowch$ ls -L /usr/local/bin/mvn
    /usr/local/bin/mvn
    
    snowch$ file /usr/local/bin/mvn
    /usr/local/bin/mvn: POSIX shell script text executable
    
    snowch$ file -b /usr/local/bin/mvn
    POSIX shell script text executable
    
  • rob
    rob over 9 years
    cool, learn something new every day.
  • Chris Snow
    Chris Snow over 9 years
    @Sree - Many thanks! I had tried the ls options, but not file. Unfortunately, neither seems to work :(
  • Sreeraj
    Sreeraj over 9 years
    @SHC Sorry, I assumed that you are on a linux box. Please add osx as one of your tags. That should get to the attention of osx users as well. I have edited the post to add the tag, but I don't have enough credits for the edit to appear immediately.
  • Chris Snow
    Chris Snow over 9 years
    @Sree - no worries, and sorry for the confusion. I've upvoted your answer anyway as it will be useful when I'm back on a linux machine.
  • tonioc
    tonioc over 9 years
    maybe check 'readlink' utility on osx.
  • Chris Snow
    Chris Snow over 9 years
    stat -f "%N -> %Y" -- /usr/local/bin/mvn worked great. Thanks!
  • Stéphane Chazelas
    Stéphane Chazelas over 9 years
    Do you know of any implementation besides modern versions of GNU ls that supports LS_COLORS that way and a --color=always and options after arguments? If on a GNU system, why would you use something that convoluted when you can use find or stat? That also probably won't work if you do some ln -s /// some-file.
  • mikeserv
    mikeserv over 9 years
    @StephaneChezales - this indicates at least that it should work similarly with a bsd ls. I remember reading that somewhere else months ago about lss all tending to accept a termcap like syntax. Good point about the ln -s /// thing - but \0NULs work as well - and -Recursively. As to why - well, it's easy to use. In some cases easier than find - and it seemed a little more on topic here than find would have been. In any case, not too many people consider it, so I mention it when I'm reminded.
  • Stéphane Chazelas
    Stéphane Chazelas over 9 years
    See the man page or there for FreeBSD. If you want to test things on FreeBSD, you can use live CDs like GhostBSD/mfsbsd in a VM.
  • mikeserv
    mikeserv over 9 years
    @StéphaneChazelas - no, i dont need to test it - definitely a wholly different animal. If you care to look, the gnu source is also linked to in the link in this answer. i wonder where i read that other thing? thanks very much for pointing that out though, that was a mistaken assumption im happy to discard. ive edited the answer.
  • Stéphane Chazelas
    Stéphane Chazelas over 9 years
    recent versions of tcsh have a ls-F builtin that supports LS_COLORS the same way as some versions of GNU ls, but it resorts to invoking ls -F if you pass any option to it, so that won't work here unless ls is GNU ls on your system.
  • mikeserv
    mikeserv over 9 years
    @StéphaneChazelas - what do you mean by that exactly - sorry i dont follow this one...? i only wrote it in because in the same google search with which i found bsd's source i also found tcsh's env docs. theyre pretty eplicit there about how it should be used - moreso than the gnu folks - most of what the tcsh docs say i gathered from the gnu source. it seems weird they would be so explicit in a shell doc about a possibly unrelated command.
  • mikeserv
    mikeserv over 9 years
    @StéphaneChazelas - ok. so you mean --color-always and $color probably. it might still work, though, one would have to be pretty devoted to doing it. a tty in between would be necessary i guess - maybe just a exec 3<>/dev/tty beforehand - (if tcshwill do it, classic cshs probably wouldnt). as i said before, i only wrote it up at all because it seemed relevant - and it can be handy in different ways for noting different file-types/extensions with different delims (or different numbers of such) especially for extensns
  • Stéphane Chazelas
    Stéphane Chazelas over 9 years
    You need -l to retrieve the symlink target, so ls-F won't do.
  • mikeserv
    mikeserv over 9 years
    @StéphaneChazelas - oh. duh. ls-F makes that obvious enough, I guess. guess it just didn't occur to me what they'd do an ls that didn't do ls stuff.
  • Jeff Schaller
    Jeff Schaller almost 9 years
    The question explicitly stated "... without having to pipe through another command ..."
  • user2332706
    user2332706 almost 9 years
    @JeffSchaller: Good point; I agree. I hope, though, that this is still of use to someone wanting an answer to the title question (without the detail in the description).
  • cfi
    cfi almost 8 years
    On an old RHEL6 system, stat is of GNU coreutils 8.4 and there it's a stat -c %N -- /usr/local/bin/mvn. To remove the quotations I had to pipe this into | perl -pe 's/['"'"'`]//g'
  • Stéphane Chazelas
    Stéphane Chazelas almost 8 years
    @cfi tr -d \'\` would be enough. Note that that RHEL system would have GNU find with which you'll have more control over.