I am in a root directory and have some folders inside:

shortcut -> 0.6

I need to list the above directories without both shortcut as well as 0.6 folder. I don't won't to search above this location or within any of these folders. I might have some files here as well but I need to ignore them. New folders with the same naming convention will be added from time to time in this directory, hence this search will be included in the bash script and will generate different results when new folders will be added and script will be run.

I've tried find -P . -maxdepth 1 -type d -ls but no luck.

  • What do you mean by "be live"?
    – Kusalananda
    Aug 10, 2018 at 18:58
  • New folders will be created there from time to time by different user.
    – mk4965
    Aug 10, 2018 at 18:59
  • Sure, but you say "this search needs to be live", and I don't know what that means.
    – Kusalananda
    Aug 10, 2018 at 19:01
  • Good point "live" was really a bad descriptor there, I've just changed it. It is a part of the script that will be producing different results as new folders will be added.
    – mk4965
    Aug 10, 2018 at 19:08

3 Answers 3


There is no way of knowing what names are the targets of symbolic links, other than to find the symbolic links and follow them.

We can therefore do this in this way (assumes bash version 4.0 or later):


# Our blacklist and whitelist associative arrays (whitelist is a misnomer, I know)
# blacklist: keyed on confirmed targets of symbolic links
# whitelist: keyed on filenames that are not symbolic links
#            nor (yet) confirmed targets of symbolic links

declare -A blacklist whitelist

for name in *; do
    if [ -L "$name" ]; then

        # this is a symbolic link, get its target, add it to blacklist
        target=$(readlink "$name")

        # flag target of link in whitelist if it's there

    elif [ -z "${blacklist[$name]}" ]; then
        # This is not a symbolic link, and it's not in the blacklist,
        # add it to the whitelist.

# whitelist now has keys that are filenames that are not symbolic
# links. If a value is zero, it's on the blacklist as a target of a
# symbolic link.  Print the keys that are associated with non-zeros.
for name in "${!whitelist[@]}"; do
    if [ "${whitelist[$name]}" -ne 0 ]; then
        printf '%s\n' "$name"

The script is supposed to be run with your directory as the current working directory, and it makes no assumptions about the names in that directory.

  • In unset whitelist[$target], whitelist[$target] is a glob, so would need to be quoted, but even then, unset whitelist"[$target]" wouldn't work for some values of $target like those containing ] and would even be a command injection vulnerability (try for instance: x='`uname>&2`x' bash -c 'typeset -A a; a[$x]=1; unset "a[$x]"'. You can actually do unset 'whitelist[$target]' though I can't tell if it would be guaranteed to work in future versions, as that's currently not documented. Aug 11, 2018 at 9:10
  • Note that that approach assumes the target is expressed as 0.6, not ./0.6 or /path/to/0.6. Aug 11, 2018 at 9:15

If you mean you want all the files of type directory that are not the target of the shortcut symlink, with zsh:

#! /bin/zsh -
printf '%s\n' *(/^e'{[[ $REPLY -ef shortcut ]]}')
  • (...): glob qualifier, to further filter files based on other criteria than just name
  • /: only files of type directory
  • ^: negate the following glob qualifiers
  • e'{shell code}': select files based on the result (exit status) of the evaluation of the shell code (where the files being considered is in $REPLY)
  • [[ x -ef y ]]: returns true if x and y point to the same file (after symlink resolution). Typically, it does that by comparing the device and inode number of both files (obtained with a stat() system call that resolves symlinks).

With GNU find (list not sorted, file names prefixed with ./):

#! /bin/sh -
find -L . ! -name . -prune -xtype d ! -samefile shortcut
  • -L: for symlinks, the target of the symlink is considered. That's needed for -samefile to do the same thing as zsh's -ef above.
  • ! -name . -prune: prune any file but .. Same as -mindepth 1 -maxdepth 1 but shorter and standard.
  • -xtype d: now that -L is on, we need -xtype to match the type of the original file before symlink resolution:
  • -samefile shortcut: true if the file is the same as shortcut (after symlink resolution with -L)

To list all directories except those that are the target of any of the symlinks in the current directories:

#! /bin/zsh -
zmodload zsh/stat
typeset -A ignore
for f (*(N@-/)) {
   zstat -H s -- $f &&

printf '%s\n' *(/^e'{zstat -H s -- $REPLY && ((ignore[$s[device]:$s[inode]]))}')

Note that the zsh-bases ones ignore the hidden files. Add the D glob qualifier or set the dotglob option to consider them.


Try using the prune switch for excluding directories, this should answer your question:

find . -path ./your-folder -prune -o -maxdepth 1 -type d -print
  • 1
    -name '*' does not do anything as it's always true.
    – Kusalananda
    Aug 10, 2018 at 19:27
  • I agree forgot to remove it Aug 10, 2018 at 19:28
  • 2
    @Kusalananda, technically, with several find implementations including GNU find, -name '*' excludes the files whose name contains sequences of bytes not forming valid characters in the current locale. IOW, it selects files whose name is valid text in the current locale. Aug 10, 2018 at 20:38
  • @StéphaneChazelas When it comes to locale-related things, I'm trusting you more than myself.
    – Kusalananda
    Aug 10, 2018 at 20:41
  • What is ./f? How does this avoid the target of the symbolic link?
    – Kusalananda
    Aug 13, 2018 at 12:05

You must log in to answer this question.

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