search en directorys principales en lugar de subdirectorys

Estoy nested en un tree de files y me gustaría encontrar qué directory principal contiene un file.

Por ejemplo, estoy en un set de repositorys Git nesteds y quiero encontrar el directory .git que controla los files en los que estoy actualmente. Espero algo como find -searchup -iname ".git"

Una versión aún más general que permite usar las opciones de 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 

Por ejemplo (suponiendo que la secuencia de commands se guarda como find_up.sh )

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

… imprimirá los nombres de todos los antepasados ​​de some_dir (incluido él mismo) hasta que se encuentre un file con el patrón.

Al utilizar readlink -f la secuencia de commands anterior seguirá los enlaces simbólicos en el path hacia arriba, como se indica en los comentarios. Puede usar realpath -s lugar, si desea seguir routes por nombre ("/ foo / bar" uploadá a "foo" incluso si "bar" es un enlace simbólico) – sin embargo, eso requiere la installation de un realpath que no es instalado por defecto en la mayoría de las plataforms.

 git rev-parse --show-toplevel 

imprimirá el directory de nivel superior del repository actual, si está en uno.

Otras opciones relacionadas:

 # `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 

Encontrar no puede hacerlo. No puedo pensar en nada más simple que un bucle de shell. (No probado, asume que no hay / /.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 

Para el caso específico de un repository git, puedes dejar que git haga el trabajo por ti.

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

Una versión generalizada de la respuesta de Gilles, el primer parámetro utilizado para search coincidencias:

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

Mantiene el uso de sym-links.

Si está utilizando zsh con globbing extendido habilitado, puede hacerlo con un 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' 

Explicación (citado de man zshexpn ):

Globo recursivo

Un componente de ruta de acceso de la forma (foo/)# coincide con una ruta que consta de cero o más directorys que coinciden con el patrón foo. Como taquigrafía, **/ es equivalente a (*/)# .

Modificadores

Después del designador de palabras opcional, puede agregar una secuencia de uno o más de los siguientes modificadores, cada uno precedido de un ':'. Estos modificadores también funcionan en el resultado de generación de nombre de file y expansión de parameters, excepto donde se indique.

  • un
    • Convierta un nombre de file en una ruta absoluta: antepone el directory actual, si es necesario, y resuelve cualquier uso de '..' y '.'
  • UN
    • Como ' a ', pero también resuelve el uso de enlaces simbólicos siempre que sea posible. Tenga en count que la resolución de '…' se produce antes de la resolución de enlaces simbólicos. Esta llamada es equivalente a a less que su sistema tenga la llamada al sistema realpath (los sistemas modernos sí lo hacen).
  • marido
    • Elimine un componente de ruta de acceso final, dejando la cabeza. Esto funciona como ' dirname '.

Créditos: Faux on #zsh para la sugerencia inicial de usar (../)#.git(:h) .

Esta versión de findup soporta la syntax "find", como la respuesta de @ sinelaw, pero también admite enlaces simbólicos sin necesidad de realpath. También es compatible con una function opcional de "stop at", por lo que esto funciona: findup .:~ -name foo … busca foo sin pasar el directory de inicio.

 #!/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 

Descubrí que trabajar con enlaces simbólicos elimina algunas de las otras opciones. Especialmente las respuestas específicas de git. A mitad de path he creado mi propio favorito de esta respuesta original que es bastante eficiente.

 #!/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" } 

Estoy usando enlaces simbólicos para mis proyectos de ir porque ir quiere código fuente en una location determinada y me gusta mantener mis proyectos en ~ / projects. Creo el proyecto en $ GOPATH / src y los enlaces simbólicos a ~ / projects. Entonces, ejecutar git rev-parse --show-toplevel imprime el directory $ GOPATH, no el directory ~ / projects. Esta solución resuelve ese problema.

Me doy count de que esta es una situación muy específica, pero creo que la solución es valiosa.

La solución de Vincent Scheib no funciona para files que residen en el directory raíz.

La siguiente versión sí lo hace, y también te permite pasar el directory inicial como el primer argumento.

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