only show the source file and target linked file using `ls`
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
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.
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 d
elete 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.