Знайдіть GNU включаючи батьківські каталоги


2

Я намагаюся змусити 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

Я не впевнений, що я вас правильно читаю, тому я просто ставлю це тут як коментар замість відповіді, але якщо ви хочете, щоб список директорій із папкою, що містить test.txt, спробуйте 'ls $ (dirname $ (знайти. -іменне main.c)) '.
Росс Ейкен

Ні, в основному моя мета полягає в тому, щоб знайти ігнорувати всі каталоги, що ведуть до потрібного файлу, але все ж видалити інші файли та каталоги в дереві.
ліквідується

Отже, ви хочете видалити всі файли, за винятком файлів (у цьому випадку) foo / bar / world, а потім видалити будь-які порожні каталоги?
Росс Ейкен

1
експортувати TST = $ (dirname $ (знайти foo-ім'я test.txt)) && знайти foo -тип f -exec bash -c 'test $ TST == $ (dirname $ 0) || rm $ 0 '{} \; && знайти foo-тип d -exec rmdir {} 2> / dev / null \; ; знайти foo
Росс Ейкен

Нічого собі, це насправді досить круте рішення. Проблема, однак, полягає в тому, що 'hello.txt' все ще існує, коли це запущено. Якщо ви зможете це також зняти, зробіть це відповіддю.
ліквідується

Відповіді:


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

0

Якщо ви знаєте точну глибину дерева (тобто ви хочете отримати файли з третьої папки далі), ви можете використовувати:

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"

На жаль, це не працює. В усьому дереві є інші файли. Наприклад, це не буде працювати, якщо ви додали файл./foo/another.txt
усувається

Додавання ./foo/another.txtне порушить його. Щось подібне foo/baz/more/something.txtламає це. Я працюю над кращим рішенням.
Робертоф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.