답변:
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
이름으로 경로를 따라 가려면 대신 사용할 수 있습니다 ( "bar"가 symlink 인 경우에도 "/ foo / bar"는 "foo"로 올라갑니다). 그러나 realpath
기본적으로 설치되어 있지 않은 설치가 필요합니다 . 대부분의 플랫폼.
realpath -s
원하는 동작을 얻는 데 사용할 수 있습니다 .
readlink
표준의 일부가 아닙니다. POSIX 쉘 기능만으로 이식 가능한 스크립트를 구현할 수 있습니다.
find
나 readlink
. $curpath
쉘 변수를 가리지 않도록 대신 비슷한 것으로 변경하는 것이 좋습니다 .
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%/*}
확장 글 로빙이 활성화 된 상태에서 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
) :
재귀 글 로빙
양식의 경로 이름 구성 요소
(foo/)#
는 패턴 foo와 일치하는 0 개 이상의 디렉토리로 구성된 경로와 일치합니다. 줄임말**/
로와 같습니다(*/)#
.수정 자
선택적인 단어 지정자 뒤에 각각 ':'이 오는 하나 이상의 다음 수정 자 시퀀스를 추가 할 수 있습니다. 이러한 수정자는 언급 된 경우를 제외하고 파일 이름 생성 및 매개 변수 확장 결과에서도 작동합니다.
- 에이
- 파일 이름을 절대 경로로 바꾸십시오. 필요한 경우 현재 디렉토리 앞에 붙고 '..'및 '.'사용을 해결합니다.
- 에이
- ' a '로 가능하지만 가능한 경우 심볼릭 링크 사용을 해결하십시오. '..'의 해상도는 심볼릭 링크의 해상도보다 먼저 발생합니다. 이 호출은 시스템에
realpath
시스템 호출이없는 한 (현대 시스템에서는) 않는 것과 같습니다 .- h
- 머리를 남기고 후행 경로 이름 구성 요소를 제거하십시오. 이것은 '
dirname
' 처럼 작동합니다 .
크레딧 : Faux
을 ( #zsh
를) 사용하는 초기 제안 에 대해 (../)#.git(:h)
.
(../)
... 아, 그리고 누가 / 무엇 Faux on #zsh
입니까?
(../)
만으로는 큰 의미가 없지만 (../)#
괄호 안의 패턴을 0 번 이상 확장하고 실제로 파일 시스템에 존재하는 패턴 만 사용하십시오. 우리는 0에서 n까지의 상위 디렉토리로 확장하고 있기 때문에 파일 시스템의 루트까지 효과적으로 검색합니다 (참고 : 패턴 뒤에 의미를 부여하기 위해 무언가를 추가하고 계몽 실행을 원할 것입니다 print -l (../)#
). 그리고 #zsh
IRC 채널이며, Faux
그것에 대한 사용자 이름입니다. Faux
해결책을 제안, 따라서 신용.
(../)#.git(/Y1:a:h)
(최신 버전의 zsh로) 처음 발견 된 것에서 멈추기
setopt extended_glob
이 버전의 findup은 @sinelaw의 답변과 같은 "find"구문을 지원하지만 realpath가 필요없는 symlink도 지원합니다. 또한 선택적 "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
symlinks로 작업하면 다른 옵션 중 일부가 죽는다는 것을 알았습니다. 특히 자식 전용 답변. 나는 절반 의 효율성 을 가진 이 독창적 인 답변에서 자신이 좋아하는 것을 만들었습니다 .
#!/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는 특정 위치에서 소스 코드를 원하고 프로젝트를 ~ / projects 아래에 유지하기 때문에 go 프로젝트에 심볼릭 링크를 사용하고 있습니다. $ GOPATH / src에 프로젝트를 만들고 ~ / projects에 심볼릭 링크합니다. 따라서 running git rev-parse --show-toplevel
은 ~ / projects 디렉토리가 아닌 $ GOPATH 디렉토리를 인쇄합니다. 이 솔루션은 해당 문제를 해결합니다.
나는 이것이 매우 구체적인 상황이라는 것을 알고 있지만 솔루션이 가치 있다고 생각합니다.
Sinelaw의 솔루션 을 POSIX로 수정 했습니다 . 심볼릭 링크를 따르지 않으며 do while 루프를 사용하여 루트 디렉토리를 검색합니다.
find-up:
#!/usr/bin/env sh
set -e # exit on error
# Use cd and pwd to not follow symlinks.
# Unlike find, default to current directory if no arguments given.
directory="$(cd "${1:-.}"; pwd)"
shift 1 # shift off the first argument, so only options remain
while :; do
# POSIX, but gets "Permission denied" on private directories.
# Use || true to allow errors without exiting on error.
find "$directory" -path "${directory%/}/*/*" -prune -o ! -path "$directory" "$@" -print || true
# Equivalent, but -mindepth and -maxdepth aren't POSIX.
# find "$directory" -mindepth 1 -maxdepth 1 "$@"
if [ "$directory" = '/' ]; then
break # End do while loop
else
directory=$(dirname "$directory")
fi
done