2

I have the following in a directory:

1/
2/
3/
4/
5/
active -> 1
previous -> 2

Those are folders, as well as two symbolic links pointing to a folder. I want to delete all folders that are not being pointed to in the symbolic links, and not delete the symbolic links. I have tried the following

find . -maxdepth 1 -mindepth 1 -type d -not -path "$(readlink -f active)" -not -path "$(readlink -f previous)"

This still returns the two directories I want excluded. What's wrong here?

2
  • I still don't want it to remove the actual directories they're pointing to though, so how do I filter them out?
    – timetofly
    Dec 20, 2017 at 17:06
  • Hm, do you want to actually remove the folders and their contents, or just filter them from the find output? You said you want to delete all that are not pointed to by the symlinks, but the find expression seems to try to filter out exactly the ones pointed to by the symlinks? So, could you edit the question to clarify a bit?
    – ilkkachu
    Dec 20, 2017 at 20:01

3 Answers 3

2

There are a couple of problems:

  1. readlink -f returns an absolute path, -path expects a relative one prefixed with ./.
  2. Some versions of readlink return a path with a trailing slash for a symlink, which is refused by find (tested with Ubuntu, not reproducible on Gentoo).

This worked for me on Ubuntu, but it may not be the most elegant solution:

find . -maxdepth 1 -mindepth 1 -type d -not -path "./$(readlink active | sed "s/\/$//")" -not -path "./$(readlink previous | sed "s/\/$//")"

Here's a slightly more straightforward alternative using realpath, tested on Gentoo; it could be the more portable one:

find . -maxdepth 1 -mindepth 1 -type d -not -path "./$(realpath --relative-to=. active)" -not -path "./$(realpath --relative-to=. previous)"
1

Since you're already using some GNUisms (-not, -mindepth, -maxdepth), you could do:

find -L . -mindepth 1 -maxdepth 1 -type d ! -xtype l \
  ! -samefile active ! -samefile previous

Then you wouldn't have to depend on the symlinks targets being in the right form (./1 if using find ., not 1, nor ././1 nor /path/to/1) and escape wildcard characters in them (if the symlink was to *, you'd need a -path './[*]' for instance).

Or with zsh:

print -rl ./*(D/e:'[[ ! $REPLY -ef active && ! $REPLY -ef previous ]]':)
0

Why not run find only in the directories you're interested in, instead of trying to filter out the others?

$ find ./active/ ./previous/

or

$ find "./$(readlink active)" "./$(readlink previous)" -maxdepth 0
./1
./2

Or if you meant you wanted find to match exactly the ones the symlinks don't point to:

$ find . -mindepth 1 -maxdepth 1  -type d  -not -path "./$(readlink active)" -not -path "./$(readlink previous)"
./3
./4
./5

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .