Is there an easy way to delete all symlinks in a directory using a script (bash with awk or similar..) ?
I have a directory containing both ordinary files and symlinks. Now I want to remove all the symlinks.
(And no, to do it manually is no option...)

I must add that this is on a set-top box and the Linux variant is OpenEmbedded (Enigma2) and so the available
linux command could be a little limited. (They are using busybox for some of the commands as well..)

I could use ls -l | grep lrw to get a list of all the symlinks, but then I'm stuck. Have tried fiddling around with awk, but I have not found any usable solution so far...

Any suggestions ?

Dani AI

Generated

A small, portable alternative when Python or specific find options are unavailable (as discussed by and ): use a tiny POSIX shell loop that only needs the shell and rm/unlink. It handles names with spaces and hidden files (with a small skip for . and ..), and avoids depending on BusyBox find variations.

# run inside the target directory
for f in * .*; do
  case "$f" in .|..) continue ;; esac
  if [ -L "$f" ]; then
    # dry-run: echo rm -- "$f"
    rm -- "$f"
  fi
done

Notes and cautions:

  • Leave the echo in place for a dry run to verify what will be removed, then remove echo to perform deletion.
  • The test [ -L "$f" ] checks for a symlink (POSIX). Quoting "$f" preserves spaces/newlines in names; rm -- protects against names beginning with -.
  • If unlink is available and you want an explicit single-link removal, use it instead of rm.
  • This loop is best for one directory. For large trees or more advanced filtering, find is still preferable where available.

Run the loop from the directory that actually contains the links (or use an absolute path in a wrapper). This approach avoids relying on BusyBox find options or a Python interpreter while staying safe for typical symlink-removal needs.

Recommended Answers

All 8 Replies

Here is a python script, if you have python

#!/usr/bin/env python
# -*-coding: utf8-*-
from __future__ import (absolute_import, division,
                        print_function, unicode_literals)

__doc__ = '''
'''

import argparse
import os

def main(args):
    d = args.directory
    for n in os.listdir(d):
        f = os.path.join(d, n)
        if os.path.islink(f):
            os.unlink(f)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
      description="""Remove symbolic links in a directory"""
    )
    parser.add_argument('directory',
        action = 'store',
        help = 'target directory',
        metavar = 'DIRECTORY',
    )
    main(parser.parse_args())

save it as rmsymlinks and make it executable

Or from the command-line you should simply be able to do this:

find ./ -type l -execdir rm {} \;

NOTE: The above will recursively find all sym-links in the current directory (and all sub-directories of the current dir) and remove them with rm. If you only want to find to search the current directory, without going into any subdirectories, you can use the -maxdepth option like this:

find ./ -maxdepth 1 -type l -execdir rm {} \;

Or you could put it into a shellscript:

#!/bin/sh

find /path/to/folder/ -maxdepth 1 -type l -execdir rm {} \;

etc...

EDIT:
For extra safety, you might also want to consider using the -i switch/option with the rm command. This will prompt whether you want to delete each individual file.
e.g.

find ./ -maxdepth 1 -type l -execdir rm -i {} \;

I wouldn't want you to accidentally hose your system using any of my suggestions! ;)

Gribouilis: Your python-script gives me an error when executing:
./rmsymlinks: line 3: syntax error: unexpected "(".

Additional systeminformation for my system (for your information):
Python 2.7.2 (default, Jul 24 2014, 08:43:32)
[GCC 4.6.4 20120303 (prerelease)] on linux2

JasonHippy: The option "execdir" is not a part of the find-command in busybox on my set-top-box. .. Sorry.

JasonHippy: Since all the symlinks are in the same directory (no subdirectories) I'm able to use your command with 'exec' replacing 'execdir'. And it works! :-)

There is no syntax error for my python. However, remove lines 3 to 8 if you want, they're not used.

Are you sure that the shebang works ?

I could try that at a later time. Now I'll stick with the other solution... :-)

Your set-top-box must either be using a different implementation or a much older version of find that doesn't have the execdir option. It was added to GNU find as a safer alternative to exec. But exec will do the trick if execdir is not available.

From looking at the man page for find, there is also the -delete option, which I've never noticed before. As you have no need for the maxdepth option, that would leave you with this:

find ./ -type l -delete

Which is even more concise and requires a little less typing. (If your set-top-boxes version of find supports it that is!)

Also, for the sake of completeness:
Depending on the age of the tools that are installed on your set-top-box, some of the commands might not be able to handle file-names containing spaces very well. So the examples I've posted so far could be problematic if any of your files contain spaces in their names.
If files with spaces in their names are a problem to remove, another alternative would be to pipe the list of files output by find to the rm command using xargs:

find ./ -type l -print0 | xargs -0 rm

Finds print0 option will print the full path of each file found, with a null character appended at the end (as opposed to a newline). And then in xargs, the -0 parameter (or --null) will cause xargs to read all characters up to the null character as a single parameter/file-name. So effectively, each filename will be separated/terminated by a null character - allowing file-names containing spaces to be passed to rm. Otherwise, the rm command would treat the spaces as separators, so a file with spaces in its name would be treated as several file-names, which could be problematic.

This might not be an issue for you, but I mentioned it just in case! :)

I'm running BusyBox version 1.19.4 (2014-07-24 09:45:52 CEST) on my set-top-box. The find-command is contained in the multi-call binary.

The command 'find ./ -type l -delete' works as well.
:-)

commented: compact solution +14
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.