Check if a file is a symlink with Bash
March 25, 2020 ‐ 5 min read
Your Bash script might need to determine if a file is a symlink or not. In Bash you can test this with the -L
operator that returns true if the file exists and is a symlink. Lets find out how this works by making a symchecker
script.
#!/bin/bash
# 1. We create a file.
touch ~/script
# 2. Link the created file above to the ~/bin directory.
ln -s ~/script ~/bin/script
# 3. Check if ~/bin/script is a symlink.
if [[ -L "$HOME/bin/script" ]]; then
echo "It's a link!"
fi
$ bash symchecker
It's a link!
So we see that works. But the script isn't perfect yet. Even though we checked for an existing symlink, this doesn't guarantee that the symlink isn't broken. Meaning the file that was symlinked might not exist anymore.
Before we proceed, lets clean up the symlink we created. Otherwise ln
will show an error message the next time we run the script. Because the link already exist.
$ unlink ~/bin/script
Lets see what I mean with broken links. We'll add a step to the symchecker script that removes the initial file but doesn't touch the symlink.
#!/bin/bash
# 1. We create a file.
touch ~/script
# 2. Link the created file above to the ~/bin directory.
ln -s ~/script ~/bin/script
# 3. Remove the initial file.
rm ~/script
# 4. Check if ~/bin/script is a symlink.
if [[ -L "$HOME/bin/script" ]]; then
echo "It's a link!"
fi
$ bash symchecker
It's a link!
And what do you know. The file where the symlink links to is removed but the test still succeeds. To include this check we use the -e
operator which checks if a file exist.
#!/bin/bash
# 1. We create a file.
touch ~/script
# 2. Link the created file above to the ~/bin directory.
ln -s ~/script ~/bin/script
# 3. Remove the initial file.
rm ~/script
# 4. Check if ~/bin/script is a symlink.
if [[ -L "$HOME/bin/script" && -e "$HOME/bin/script" ]]; then
echo "It's a link!"
else
echo "Might be a link, but it doesn't exist!"
fi
$ bash symchecker
ln: failed to create symbolic link '/home/koen/bin/script': File exists
Might be a link, but it doesn't exist!
So that did the trick. But uh oh, we didn't unbind the symlink before. Now that we have a check for valid symlinks, we might as well safe us some time and clean up a broken link if we find one.
#!/bin/bash
# 1. We create a file.
touch ~/script
# 2. Link the created file above to the ~/bin directory.
ln -s ~/script ~/bin/script
# 3. Remove the initial file.
rm ~/script
# 4. Check if ~/bin/script is a symlink.
if [[ -L "$HOME/bin/script" ]]; then
if [[ -e "$HOME/bin/script" ]]; then
echo "It's a link!"
else
unlink ~/bin/script
echo "Link was broken, I cleaned it up!"
fi
else
echo "Not a link!"
fi
$ bash symchecker
ln: failed to create symbolic link '/home/koen/bin/script': File exists
Link was broken, I cleaned it up!
So it look liked it worked! But we still see the error message from ln
. Actually this is because the first time we run the script, it was still there from the previous version from the symchecker script. In which we didn't clean up. To double check, we can it a second try.
$ bash symchecker
Link was broken, I cleaned it up!
Yup, that looks better. But... all what we have now is a script that:
- Creates a file
- Creates a symlink to that file
- Removes that file
- Removes the symlink
So the end result is basically nothing.
Lets make the script sort of usable by letting it expect a file path as parameter. So we will end up with a script that checks if the specified file is a symlink or not and clean it up if it happens to be broken.
#!/bin/bash
# 1. Store the first parameter to the script in a variable.
path="$1"
# 2. Now that we expect a parameter, lets check if it was provided.
if [[ -z "$path" ]]; then
echo "Script expects a parameter"
exit 1
fi
# 3. Check if the parameter is a symlink.
if [[ -L "$path" ]]; then
# 4. Check if it links to a valid path.
if [[ -e "$path" ]]; then
echo "$path is a valid link!"
else
unlink "$path"
echo "Cleaned up broken link: $path"
fi
else
echo "$path is not a symlink."
fi
$ bash symchecker ~/brokenlink
Cleaned up broken link: ~/brokenlink
There you go. An advanced symlink checker and broken link cleaner in one. All that's left is putting the script in your PATH and make is executable with chmod.
Learning more
The best way to learn more is to use Bash. A lot. Don't forget that Google is your friend.
In case you learn well from books I would recommend these.