How to check if a symlink exists
Asked Answered
R

8

296

I'm trying to check if a symlink exists in bash. Here's what I've tried.

mda=/usr/mda
if [ ! -L $mda ]; then
  echo "=> File doesn't exist"
fi


mda='/usr/mda'
if [ ! -L $mda ]; then
  echo "=> File doesn't exist"
fi

However, that doesn't work. If '!' is left out, it never triggers. And if '!' is there, it triggers every time.

Reahard answered 23/4, 2011 at 21:27 Comment(1)
for what its worth, if you use [[ ! -D $mda ]] works just fine..Wang
A
427

-L returns true if the "file" exists and is a symbolic link (the linked file may or may not exist). You want -f (returns true if file exists and is a regular file) or maybe just -e (returns true if file exists regardless of type).

According to the GNU manpage, -h is identical to -L, but according to the BSD manpage, it should not be used:

-h file True if file exists and is a symbolic link. This operator is retained for compatibility with previous versions of this program. Do not rely on its existence; use -L instead.

Arsyvarsy answered 23/4, 2011 at 21:31 Comment(13)
I'm looking to see if a symlink DOESN'T exist. !-h or !-L should work for symlinks, !-e should work otherwise.Reahard
To help anyone who finds this via Google as I did, the full syntax using ! is if ! [ -L $mda ]; then .... fi i.e. put the exclamation mark outside the square brackets.Aldas
Just wanted to add a little something to the tip given by @Sam; when doing these sorts of operations make sure to put your file name in quotes, to prevent issues with whitespaces. e.g. if [ ! -L "$mda" ]; then ... fi (note: if [ ! ... ] and if ! [ ... ] are identical :)Nihility
do you really see a difference between -L and -h ? in my bash ( version 4.2.53(1)-release (x86_64-redhat-linux-gnu ) man bash is identical for both -L and -h and they behave the same, ie they check that file actualy is a link and don't care whether the linked to file exists or not.Grata
Yes, -L and -h are the same. man test also confirms this.Counterinsurgency
Anybody has an idea how to check whether the target file exists?Art
@Counterinsurgency - any idea why they might be synonymous in the first place? The best reason my googling came up with is "because it's bash"Cassidy
@Cassidy No idea… I thought I remembered some commands where -h was to do with symlinks, but I can't seem to find them now. cp -H is similar I guess, although mostly -h is to show the help. You should ask it as a question (perhaps in Unix/Linux)!Counterinsurgency
@Cassidy man test on BSD's test provided some insight about -h: This operator is retained for compatibility with previous versions of this program. Do not rely on its existence; use -L instead. As for why they changed to -L over -h, I have no ideaChristian
@TomášZato -e $(readlink -f $symlink) would check if the linked file exists, but has the caveat that is also return true if $symlink exists but is not actually a symlink.Christian
it seems if a link is broken, -e doesn't work but only -L can tell if the link exist (though the linked file doesn't exist). Is there anyway to test if a file/or even broken link exist ?Adjudication
-f also return true if the file is a symbolic link and target is exist.Coquet
@Adjudication Just ran into a super annoying bug because of this. This detail should probably be added to the answer to help others in the future.Rosenberg
S
108

You can check the existence of a symlink and that it is not broken with:

[ -L ${my_link} ] && [ -e ${my_link} ]

So, the complete solution is:

if [ -L ${my_link} ] ; then
   if [ -e ${my_link} ] ; then
      echo "Good link"
   else
      echo "Broken link"
   fi
elif [ -e ${my_link} ] ; then
   echo "Not a link"
else
   echo "Missing"
fi

-L tests whether there is a symlink, broken or not. By combining with -e you can test whether the link is valid (links to a directory or file), not just whether it exists.

Sepulveda answered 23/3, 2016 at 13:48 Comment(3)
-L test if there is a symlink, broken or not. By combining with -e it is possible to test if the link is also valid (linking to a directory or file). Up-voting this solutions, since I find it important to capture this aspect.Counterblast
Thanks ! I'm struggling with the logic behind if, this post really helped me ! +1Tensile
bash friendly: if [[ -L "${my_link}" ]]; then ...Sweatt
O
40

-L is the test for file exists and is also a symbolic link

If you do not want to test for the file being a symbolic link, but just test to see if it exists regardless of type (file, directory, socket etc) then use -e

So if file is really file and not just a symbolic link you can do all these tests and get an exit status whose value indicates the error condition.

if [ ! \( -e "${file}" \) ]
then
     echo "%ERROR: file ${file} does not exist!" >&2
     exit 1
elif [ ! \( -f "${file}" \) ]
then
     echo "%ERROR: ${file} is not a file!" >&2
     exit 2
elif [ ! \( -r "${file}" \) ]
then
     echo "%ERROR: file ${file} is not readable!" >&2
     exit 3
elif [ ! \( -s "${file}" \) ]
then
     echo "%ERROR: file ${file} is empty!" >&2
     exit 4
fi
Oxygen answered 23/4, 2011 at 21:38 Comment(4)
-e "${file}" fails if the symlink exists but its target does not exist.Salzburg
Same result as Flimm. I'm on OS X. For me, -L and -h work for symlinks, but not -e or -f.Cila
@Flimm, so if I just want to test if a filename is taken (whether it's a file or symlink without target existing) what's the best way to do it? apparently -e doesn't workAdjudication
@Adjudication maybe [ -L $file_or_link ] || [ -e $file_or_link ]?Esme
T
18

Maybe this is what you are looking for. To check if a file exist and is not a link.

Try this command:

file="/usr/mda" 
[ -f $file ] && [ ! -L $file ] && echo "$file exists and is not a symlink"
Traffic answered 23/4, 2011 at 21:31 Comment(0)
D
14

How about using readlink?

# if symlink, readlink returns not empty string (the symlink target)
# if string is not empty, test exits w/ 0 (normal)
#
# if non symlink, readlink returns empty string
# if string is empty, test exits w/ 1 (error)
simlink? () {
  test "$(readlink "${1}")";
}

FILE=/usr/mda

if simlink? "${FILE}"; then
  echo $FILE is a symlink
else
  echo $FILE is not a symlink
fi
Dafna answered 6/1, 2017 at 3:4 Comment(0)
W
5

Is the file really a symbolic link? If not, the usual test for existence is -r or -e.

See man test.

Wendy answered 23/4, 2011 at 21:31 Comment(0)
L
5
  1. first you can do with this style:

    mda="/usr/mda"
    if [ ! -L "${mda}" ]; then
      echo "=> File doesn't exist"
    fi
    
  2. if you want to do it in more advanced style you can write it like below:

    #!/bin/bash
    mda="$1"
    if [ -e "$1" ]; then
        if [ ! -L "$1" ]
        then
            echo "you entry is not symlink"
        else
            echo "your entry is symlink"
        fi
    else
      echo "=> File doesn't exist"
    fi
    

the result of above is like:

root@linux:~# ./sym.sh /etc/passwd
you entry is not symlink
root@linux:~# ./sym.sh /usr/mda 
your entry is symlink
root@linux:~# ./sym.sh 
=> File doesn't exist
Luminescent answered 17/9, 2018 at 15:9 Comment(1)
The first invocation is wrong if the file exists but is not a link, or is a dangling link. The second is wrong if the path is a dangling symlink.Tidewaiter
P
4

If you are testing for file existence you want -e not -L. -L tests for a symlink.

Patchy answered 23/4, 2011 at 21:30 Comment(2)
I'm looking to see if a symlink DOESN'T exist. !-h or !-L should work for symlinks, !-e should work otherwise.Reahard
What you want is not clear. The file exists and is not a symlink? Then test both -e and !-h .Patchy

© 2022 - 2024 — McMap. All rights reserved.