Используйте find, чтобы получить все папки, у которых нет подпапки.git

Как использовать find, чтобы получить все папки, которые не имеют папки.git?

На этой структуре::

$ tree -a -d -L 2
.
├── a
│   └── .git
├── b
│   ├── b1
│   └── b2
├── c
└── d
    └── .git
        ├── lkdj
        └── qsdqdf

Это::

$ find . -name ".git"  -prune -o -type d -print
.
./a
./b
./b/b1
./b/b2
./c
./d
$

получить все папки, кроме.git

Я хотел бы получить это::

$ find . ...
.
./b
./b/b1
./b/b2
./c
$

3 ответа

Решение

Это неэффективно (запускает кучу подпроцессов), но следующее будет работать с GNU или современным BSD find:

find . -type d -exec test -d '{}/.git' ';' -prune -o -type d -print

Если вам не гарантировано иметь find с любой функциональностью, не гарантированной в стандарте POSIX, вам может потребоваться еще больше потери эффективности (чтобы сделать {} свой собственный токен, а не подстрока, с помощью оболочки, запускающей тест):

find . -type d -exec sh -c 'test -d "$1/.git"' _ '{}' ';' -prune -o -type d -print

Это работает с помощью -exec в качестве предиката, запускающего тест, который find не имеет встроенной поддержки.

Обратите внимание на использование неэффективных -exec [...] {} [...] \; а не более эффективный -exec [...] {} +; так как последний передает несколько имен файлов каждому вызову, он не имеет возможности вернуть отдельные результаты для каждого имени файла и поэтому всегда оценивается как истина.

Если вы не возражаете против использования временного файла, то:

find . -type d -print > all_dirs
fgrep -vxf <(grep '/\.git$' all_dirs | sed 's#/\.git$##') all_dirs | grep -vE '/\.git$|/\.git/'
rm all_dirs
  • Первый шаг - получить все пути подкаталогов в файл all_dirs.
  • Вторые шаги отфильтровывают каталоги, которые имеют подкаталог.git, а также подкаталоги.git. -x опция необходима, потому что нам нужно исключить только те строки, которые полностью совпадают.

Это будет немного более эффективным по сравнению с ответом Чарльза в том, что он не запускает так много подпроцессов. Тем не менее, это даст неверный вывод, если в любом из каталогов будет символ перевода строки.

Если вы хотите найти только верхние каталоги, добавьте опцию-maxdepth 1нравиться

      $ find . -type d -exec test -d '{}/.git' ';' -maxdepth 1 -prune -o -type d -print
.
./b
./c
$
Другие вопросы по тегам