найти поиск в родительских каталогах вместо подкаталогов

Я глубоко вложен в дерево файлов, и я хотел бы найти, какой родительский каталог содержит файл.

Например, я вхожу в набор вложенных репозиториев Git и хочу найти каталог .git, управляющий файлами, в которых я сейчас. Надеюсь на что-то вроде find -searchup -iname ".git"

8 Solutions collect form web for “найти поиск в родительских каталогах вместо подкаталогов”

Еще более общая версия, которая позволяет использовать параметры find :

 #!/bin/bash set -e path="$1" shift 1 while [[ $path != / ]]; do find "$path" -maxdepth 1 -mindepth 1 "$@" # Note: if you want to ignore symlinks, use "$(realpath -s "$path"/..)" path="$(readlink -f "$path"/..)" done 

Например (если скрипт сохраняется как find_up.sh )

 find_up.sh some_dir -iname "foo*bar" -execdir pwd \; 

… будет печатать имена всех some_dir (включая самих себя) до / в которых найден файл с шаблоном.

При использовании readlink -f приведенный выше сценарий будет следовать символическим ссылкам на пути вверх, как отмечено в комментариях. Вы можете использовать realpath -s вместо этого, если вы хотите следовать дорожкам по имени («/ foo / bar» будет идти до «foo», даже если «bar» является символической realpath ), однако для этого требуется установка realpath которая не является установленный по умолчанию на большинстве платформ.

 git rev-parse --show-toplevel 

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

Другие связанные варианты:

 # `pwd` is inside a git-controlled repository git rev-parse --is-inside-work-tree # `pwd` is inside the .git directory git rev-parse --is-inside-git-dir # path to the .git directory (may be relative or absolute) git rev-parse --git-dir # inverses of each other: # `pwd` relative to root of repository git rev-parse --show-prefix # root of repository relative to `pwd` git rev-parse --show-cdup 

Найти не могу. Я не могу придумать ничего проще, чем цикл оболочки. (Непроверенный, предполагает, что нет /.git )

 git_root=$(pwd -P 2>/dev/null || command pwd) while [ ! -e "$git_root/.git" ]; do git_root=${git_root%/*} if [ "$git_root" = "" ]; then break; fi done 

Для конкретного случая репозитория git вы можете позволить git выполнить эту работу за вас.

 git_root=$(GIT_EDITOR=echo git config -e) git_root=${git_root%/*} 

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

 find-up () { path=$(pwd) while [[ "$path" != "" && ! -e "$path/$1" ]]; do path=${path%/*} done echo "$path" } 

Сохраняет использование символических ссылок.

Если вы используете zsh с включенным расширенным включением, вы можете сделать это с помощью oneliner:

 (../)#.git(:h) # relative path to containing directory, eg. '../../..', '.' (../)#.git(:a) # absolute path to actual file, eg. '/home/you/src/prj1/.git' (../)#.git(:a:h) # absolute path to containing directory, eg. '/home/you/src/prj1' 

Объяснение (цитируется от man zshexpn ):

Рекурсивное глобирование

Компонент pathname формы (foo/)# соответствует пути, состоящему из нулей или более каталогов, соответствующих шаблону foo. Как сокращенное выражение **/ эквивалентно (*/)# .

Модификаторы

После необязательного указателя слов вы можете добавить последовательность из одного или нескольких из следующих модификаторов, каждому из которых предшествует символ «:». Эти модификаторы также работают на результат генерации имени файла и расширения параметров, за исключением случаев, когда это указано.

    • Поверните имя файла в абсолютный путь: при необходимости добавьте текущий каталог и разрешите любое использование «..» и «.».
    • Как « а », но также разрешать использование символических ссылок, где это возможно. Обратите внимание, что разрешение разрешения «..» происходит до разрешения символических ссылок. Этот вызов эквивалентен a, если ваша система не имеет системный вызов realpath (современные системы делают).
  • час
    • Удалите компонент конечного пути, оставив голову. Это работает как « dirname ».

Кредиты: Faux на #zsh для первоначального предложения использования (../)#.git(:h) .

Эта версия findup поддерживает синтаксис «find», например, ответ @ sinelaw, но также поддерживает символические ссылки, не требуя realpath. Он также поддерживает дополнительную функцию «stop at», поэтому это работает: findup .:~ -name foo … ищет foo без передачи домашнего каталога.

 #!/bin/bash set -e # get optional root dir IFS=":" && arg=($1) shift 1 path=${arg[0]} root=${arg[1]} [[ $root ]] || root=/ # resolve home dir eval root=$root # use "cd" to prevent symlinks from resolving cd $path while [[ "$cur" != "$root" && "$cur" != "/" ]]; do cur="$(pwd)" find "$cur/" -maxdepth 1 -mindepth 1 "$@" cd .. done 

Я обнаружил, что работа с символическими ссылками убивает некоторые другие параметры. Особенно конкретные ответы git. Я на полпути создал свой собственный любимый из этого оригинального ответа, который довольно эффективен.

 #!/usr/bin/env bash # usage: upsearch .git function upsearch () { origdir=${2-`pwd`} test / == "$PWD" && cd "$origdir" && return || \ test -e "$1" && echo "$PWD" && cd "$origdir" && return || \ cd .. && upsearch "$1" "$origdir" } 

Я использую символические ссылки для моих проектов go, потому что go хочет исходный код в определенном месте, и мне нравится поддерживать мои проекты в ~ / проектах. Я создаю проект в $ GOPATH / src и символически привязываю его к ~ / projects. Таким образом, запуск git rev-parse --show-toplevel toplevel выводит каталог $ GOPATH, а не каталог ~ / projects. Это решение решает эту проблему.

Я понимаю, что это очень конкретная ситуация, но я думаю, что решение ценно.

Решение Vincent Scheib не работает для файлов, которые находятся в корневом каталоге.

Следующая версия делает, а также позволяет передавать начальный каталог в качестве первого аргумента.

 find-up() { path="$(realpath -s "$1")" while ! [ -e "$path"/"$2" ] && [ -n "$path" ]; do path="${path%/*}" done [ -e "$path"/"$2" ] && echo "$path"/"$2" } 
  • Используйте команду find для преобразования файлов разметки в html
  • OpenBSD: переместить каталоги, большие, чем X, в новый каталог
  • Regex in find - OS X
  • Удалить рекурсивные файлы, которые НЕ соответствуют регулярному выражению
  • Как я могу искать и выполнять сценарий оболочки из другого?
  • Найти файлы и рекурсивно добавить текст к ним
  • Разделить имя файла и путь внутри опции -exec команды find
  • Переименуйте сразу несколько каталогов
  • Как удалять временные метки файлов на 3 месяца (для дерева каталогов)?
  • Можно ли безопасно использовать `find -exec sh -c`?
  • find: чернослив не игнорирует указанный путь
  • Linux и Unix - лучшая ОС в мире.