zsh 별칭 함수를 파이프에 전달하는 방법

zsh 별칭 함수를 파이프에 전달하는 방법

zsh 별칭이 있습니다.

gitbs() {
    git branch | grep -- $1
}

다음과 같이 결과를 git checkout에 전달하고 싶습니다. git checkout | gitbs state 어떻게 하면 이 작업을 수행할 수 있나요?

답변1

쉘 파이프는 한 명령의 출력을 다른 명령의 입력으로 전달합니다. 여기서는 도움이 되지 않습니다. 명령의 출력을 명령줄 인수로 다른 명령에 전달하려고 합니다. 이를 수행하는 도구는 다음과 같습니다.명령 대체. 그래서 기본 아이디어는

git checkout "$(gitbs state)"

(여전히 파이프이지만 파이프의 읽기 끝은 셸 자체입니다. 출력을 읽은 다음 해당 출력을 포함하는 명령줄을 구성합니다.)

그러나 의 출력은 gitbs state전달하기에 올바른 형식이 아닙니다 git checkout. 분기 이름과 동일한 줄에 추가 공백이 있고 때로는 구두점이 있습니다. (색상 형식 지정 코드도 있지만 출력이 터미널로 전달되거나 git이 자동으로 호출기를 호출하는 경우에만 해당되며 출력이 파이프인 경우는 아닙니다.) 또한 일치하는 분기가 없거나 여러 분기가 없으면 이상한 결과가 나타납니다. 정보의 오류 git checkout.

gitbs이 문제를 해결하려면 원래 분기 이름을 출력으로 생성하도록 변경할 수 있습니다 . 다음은 출력이 터미널인 경우 사람을 위해 예쁜 형식을 유지하고, 그렇지 않으면 한 줄에 분기 이름을 인쇄하는 버전입니다. 그것은 사용한다git for-each-ref지점 이름을 열거합니다. 이것조건식 -t 1표준 출력이 터미널인지 테스트합니다.

gitbs () {
  if [[ -t 1 ]]; then
    git branch
  else
    git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*'
  fi | grep -- "$1"
}

이 정의로 gitbs그게 git checkout "$(gitbs state)"전부입니다.

명령 대체 주위에 큰따옴표가 있습니다. 큰따옴표( git checkout $(gitbs state))가 없으면 출력은 공백에서 별도의 인수로 분할되므로 여러 분기가 일치하면 결과 명령은 체크 아웃하는 대신 파일의 현재 버전을 git checkout foobar1 foobar2if의 버전으로 덮어쓰게 됩니다. 이름의 파일이 존재합니다.foobar1foobar2foobar1foobar2

gitbs이러한 함정을 피하려면 일치하는 단일 분기가 필요한 다른 버전을 정의하는 것이 좋습니다 . 일치하는 분기가 0개 이상 있으면 현재 분기에 대한 추가 메시지가 계속 표시되지만 더 명확한 오류 메시지가 표시됩니다 git checkout. 이 함수는 일치하는 분기 목록을대량으로

gitbs1 () {
  local branches
  branches=($(git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*' | grep "$1"))
  if ((#branches == 0)); then
    echo "No branch contains '$1'" >&2
    return 3
  fi
  if ((#branches > 1)); then
    echo "Multiple branches match '$1':" >&2
    print -lr $branches >&2
    return 3
  fi
  echo $branches
}

그러면 자신감 있게 글을 쓸 수 있습니다 git checkout $(gitbs1 state).


이 옵션을 켜면glob_complete(즉 setopt glob_complete, .zshrc) 그런 다음 입력할 수 있습니다.

자식 브랜치 *foo*Tab

*foo*일치하는 분기의 이름(있는 경우)으로 대체됩니다. 일치하는 분기가 여러 개 있는 경우 일반(접두사) 완료와 동일한 종류의 메뉴 또는 루프 동작이 발생합니다.

답변2

이것은 별칭이 아니라 함수입니다.

명령 출력의 단어를 인수로 다른 명령에 전달하려는 경우 명령 대체는 다음과 같습니다.

git checkout $(gitbs state)

캡처된 출력 gitbs state(여기서는 함수, 별칭 또는 외부 명령인지는 중요하지 않음)을 가져오고 후행 줄 바꿈, 구분 문자를 제거 $IFS하고 결과 단어를 별도의 인수로 git checkout1 에 전달합니다.

분할 결과의 첫 번째 단어만 전달합니다.

git checkout ${$(gitbs state)[1]}

전체 출력(후행 줄 바꿈 제외)을 다음과 같이 전달합니다.하나매개변수 git checkout는 다음을 참조하세요.

git checkout "$(gitbs state)"

$IFS문자 대신 임의의 문자열로 분할하려면 s매개변수 확장 플래그를 사용하십시오(또는 f개행으로 분할).

git checkout ${(f)"$(gitbs state)"}

(빈 요소는 제거됩니다.)

xargs명령은 이러한 목적으로 사용될 수 있지만 분할은 xargs매우 특정한 방식으로 수행되며 xargs외부 명령(셸 내장 또는 기능이 아님)만 실행할 수 있습니다.

gitbs state | xargs git checkout

xargs 많은 수의 단어가 출력되는 경우(단일 명령줄에 들어갈 수 있는 것보다 많은 단어) 이 작업은 여러 번 실행될 수 있습니다 git checkout.gitbs state


set -o noglob1 Bourne과 같은 다른 쉘에서는 결과 단어에 대한 이 작업을 방지하기 위해 와일드카드( )를 비활성화해야 합니다 . zshsh/ksh 에뮬레이션 모드가 아닌 이상 적용되지 않습니다.

관련 정보