
Я пытаюсь заставить 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"