17

How do I remove all symlinks in a folder (dozens of them) at once? It's not practical to insert every single one of them by hand when using unlink or rm.

1
  • What do you mean by "folder"? Are you just talking about what Linux calls directories, or do you have some other usage in mind?
    – tchrist
    Aug 8, 2022 at 14:46

4 Answers 4

30

You can use the find-command to do that:

find /path/to/directory -maxdepth 1 -type l -delete

To be on the safe side, check first without the -delete-option:

find /path/to/directory -maxdepth 1 -type l

-maxdepth 1 ensures that find will look only in /path/to/directory but not in it's subfolders for symlinks. Feel free to take a look at man find.

1
  • 1
    Thanks. "find /path/to/directory -maxdepth 1 -type l -delete" did the trick. Aug 8, 2022 at 8:44
14

List the links in the current directory alias folder and check that you really want to remove them,

find -type l -ls                  # search also in subdirectories

find -maxdepth 1 -type l -ls      # search only in the directory itself

If things look good, and you want to delete these links, run

find -type l -delete              # delete also in subdirectories

find -maxdepth 1 -type l -delete  # delete only in the directory itself

If you want to delete interactively, you can use the following command line (this is safer)

find -type l -exec rm -i {} +              # delete also in subdirectories

find -maxdepth 1 -type l -exec rm -i {} +  # delete only in the directory itself
5
  • 2
    With the first interactive option, you may also want to use -depth to ensure depth-first traversal - that is, that it asks about root/symlink1/symlink2 before root/symlink1.
    – minnmass
    Aug 8, 2022 at 3:24
  • 1
    @minnmass: But find won't follow symlinks by default, so it won't find root/symlink1/symlink2 - it'll find root/symlink1, but not try to look for things under it (even if it's a link to a directory).
    – psmears
    Aug 8, 2022 at 11:02
  • @psmears: derp; I'm too used to treating symlinks to directories as just directories, and the abstraction broke. ... never mind.
    – minnmass
    Aug 8, 2022 at 13:42
  • Was going to comment exactly this but not quite as complete... beat me to it 🙃
    – dolt
    Aug 9, 2022 at 19:25
  • 1
    @minnmass 'find' by default won't search directories that are symlinks to outside the root dir. You can use -L to tell it to dereference symlinks which iirc works for directories.
    – dolt
    Aug 9, 2022 at 19:29
10

For users of the Z shell, rm *(@) will achieve this.

Zsh supports glob qualifiers that limit the type of files a glob (such as *) applies to, for example (/) for directories, (x) for executable files, (L0) for empty files, and (@) for symlinks.

For symlinks:

% ll
lrwxrwxrwx 1 test test 3 Aug  8 15:51 bar -> foo
-rw-r--r-- 1 test test 0 Aug  8 15:51 baz
-rw-r--r-- 1 test test 0 Aug  8 15:52 foo
lrwxrwxrwx 1 test test 4 Aug  8 15:51 qux -> /etc/ 

% rm *(@)                                                                         
removed 'bar'
removed 'qux'

% ll                                                                              
-rw-r--r-- 1 test test 0 Aug  8 15:51 baz
-rw-r--r-- 1 test test 0 Aug  8 15:52 foo
1
  • 2
    Nice :-) … probably a dry-run with echo first before using rm might be a good idea to be on the safe side.
    – Raffa
    Aug 8, 2022 at 15:47
7

In bash(and most shells) … The builtin command test and its variant [ has an option -h(or -L if it’s easier to remember) that will return success(exit 0) for a file if it exists and is a symbolic link … So it can be used in a shell loop like so:

for f in *
    do
    if [ -h "$f" ]
        then 
        echo rm -- "$f"
    fi
done

or a one liner like so:

for f in *; do if [ -h "$f" ]; then echo rm -- "$f"; fi done

or even more compact(bash specific … although reported to be working in zsh and ksh as well) like so:

for f in *; { [ -h "$f" ] && echo rm -- "$f"; }

Notice:

echo is there for a dry-run ... When satisfied with the output, remove echo to delete the links.

2
  • 1
    A bit more compact: [ -h "$f" ] && rm -- "$f" Aug 8, 2022 at 16:06
  • @PabloBianchi Yep, … only a bit though :-) … But, can be compacted more if the command grouping constructs {} are used with the for loop … askubuntu.com/a/1419265
    – Raffa
    Aug 8, 2022 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.