GNU find включает родительские каталоги

GNU find включает родительские каталоги

Я пытаюсь заставить GNU найти записи исключения ДО указанного имени файла.

Возьмем для примера это дерево:

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

(В каталогах и других каталогах также может быть куча других файлов world, поэтому я просто не ищу hello.txt).

Мне нужно сопоставить все, кроме «test.txt» и его родительских каталогов.

Вывод должен быть просто foo/bar/world/hello.txt.

Эта команда выдает правильные результаты, но она довольно запутанная и выдала бы неправильные результаты, если бы существовало несколько каталогов с одинаковыми именами:

find * ! -name test.txt -a ! -name foo -a ! -name bar -a ! -name world

решение1

Скажите, что findвас интересуют только файлы, а не каталоги.

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

Обновлять:

Предположим, у нас есть немного более сложный пример:

$ 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

Если ваша цель — удалить что-то, вам нужно указать, -depthчтобы файлы отображались перед их каталогами:

$ 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

Если вы знаете путь, который хотите сохранить, мы можем разработать регулярное выражение, которое будет соответствовать его частям:

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

Затем мы можем просто отменить регулярное выражение, чтобы получить то, что нужно удалить:

$ 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

решение2

Если вы знаете точную глубину дерева (т. е. хотите получить файлы, начиная с третьей папки), вы можете использовать:

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

С вашей структурой каталогов я получаю:

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

Это именно то, чего вы ожидаете.


EDIT: это должно быть лучше (но уродливее!). Он находит каталог, в котором test.txtнаходится и находит все файлы в нем. Преимущество в том, что он полностью независим от родительских путей, он автоматически вычисляет их.

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

Лучше использовать многострочный вариант:

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

Связанный контент