2

I am trying to make GNU find exclude entries UP TO the specified file name.

Take this sample tree:

./foo
./foo/another.txt
./foo/bar
./foo/bar/world
./foo/bar/world/test.txt
./foo/bar/world/hello.txt

(There would be a bunch of other files in the world and other directories as well, that is why I am not simply searching for hello.txt).

I want match everything but 'test.txt' and its parent directories.

The output should simply be foo/bar/world/hello.txt.

This command produces the right results, but it is pretty messy, and would produce the wrong results if there were several directories with the same names:

find * ! -name test.txt -a ! -name foo -a ! -name bar -a ! -name world
5
  • I'm not sure I'm reading you right, so I'm just putting this here as a comment instead of an answer, but if you want a directory listing of the folder containing test.txt, try 'ls $(dirname $(find . -name main.c))'.
    – Ross Aiken
    Jan 29, 2014 at 16:11
  • No, basically my goal is for find to ignore all of the directories leading up to the wanted file, but still delete other files and directories in the tree.
    – elimirks
    Jan 29, 2014 at 16:14
  • So you want to delete all files except for the ones in (in this case) foo/bar/world, and then delete any empty directories?
    – Ross Aiken
    Jan 29, 2014 at 20:48
  • 1
    export TST=$(dirname $(find foo -name test.txt)) && find foo -type f -exec bash -c 'test $TST == $(dirname $0) || rm $0' {} \; && find foo -type d -exec rmdir {} 2>/dev/null \; ; find foo
    – Ross Aiken
    Jan 29, 2014 at 21:09
  • Wow, that is actually a pretty cool solution. The issue, though, is that 'hello.txt' still exists when this in run. If you could get it to remove that as well, make this an answer.
    – elimirks
    Jan 30, 2014 at 13:49

2 Answers 2

1

Tell find you're only interested in files, not directories.

find ./foo -type f ! -name test.txt

Update:

Suppose we have this slightly more complex example:

$ find ./foo
./foo
./foo/baz
./foo/baz/b.csv
./foo/baz/a.txt
./foo/bar
./foo/bar/c.txt
./foo/bar/world
./foo/bar/world/hello.txt
./foo/bar/world/test.txt

If your goal is to delete things, you need to specify -depth so files are seen before their directories:

$ find ./foo -depth
./foo/baz/b.csv
./foo/baz/a.txt
./foo/baz
./foo/bar/c.txt
./foo/bar/world/hello.txt
./foo/bar/world/test.txt
./foo/bar/world
./foo/bar
./foo

If you know the path you want to keep, we can devise a regular expression that matches bits of it:

$ find ./foo -depth -regextype posix-extended -regex '^\./foo(/bar(/world(/test.txt)?)?)?'
./foo/bar/world/test.txt
./foo/bar/world
./foo/bar
./foo

Then we can just negate the regex to get the stuff you want to remove:

$ find ./foo -depth -regextype posix-extended ! -regex '^\./foo(/bar(/world(/test.txt)?)?)?'
./foo/baz/b.csv
./foo/baz/a.txt
./foo/baz
./foo/bar/c.txt
./foo/bar/world/hello.txt
0
0

If you know the exact depth of the tree (i.e., you want to get the files from the third folder onwards), you can use:

find . -mindepth $depth ! -name test.txt

With your directory structure, I get:

$ find . -mindepth 4 ! -name test.txt
./foo/bar/world/hello.txt

Which is exactly what you expect.


EDIT: this should be better (but uglier!). It finds the directory where test.txt is located and finds all files in it. The advantage is that it is completely independent to the parent paths, it will automatically calculate them.

EXCLUDEFNAME="test.txt"; find $(find . -name "$EXCLUDEFNAME" -exec dirname {} \; -quit) -mindepth 1 ! -name "$EXCLUDEFNAME"

Multi-line is better:

EXCLUDEFNAME="test.txt"
targetpath="$(find . -name "$EXCLUDEFNAME" -exec dirname {} \;)"
find "$targetpath" -mindepth 1 ! -name "$EXCLUDEFNAME"
2
  • Unfortunately, this wouldn't work. There are other files throughout the tree. For instance, it wouldn't work if you added the file ./foo/another.txt
    – elimirks
    Jan 28, 2014 at 16:43
  • Adding ./foo/another.txt won't break it. Something like foo/baz/more/something.txt breaks it. I'm working on a better solution.
    – Robertof
    Jan 28, 2014 at 16:46

You must log in to answer this question.

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