zsh의 함수 호출 컨텍스트: bash `caller`와 동일

zsh의 함수 호출 컨텍스트: bash `caller`와 동일

Bash에서는 다음과 같이 작성할 수 있습니다.

caller 0

그리고 받았다방문객상황별:

  • 전화 번호
  • 기능
  • 스크립트 이름

이는 디버깅에 매우 유용합니다. 반면:

yelp () { caller 0; }

yelp그런 다음 어떤 코드 줄에 도달했는지 확인하기 위해 글을 쓸 수 있습니다 .

caller 0다음 과 같이 구현할 수 있습니다 bash.

echo "${BASH_LINENO[0]} ${FUNCNAME[1]} ${BASH_SOURCE[1]"

caller 0에서와 동일한 출력을 어떻게 얻을 수 있습니까 zsh?

답변1

내장은 없는 것 같아요주문하다동일하지만 이 네 가지 변수의 일부 조합zsh/매개변수 모듈다음을 사용할 수 있습니다:

funcfiletrace

EVAL_LINENO이 배열에는 현재 함수, 소스 파일 또는 (설정된 경우) 명령이 호출된 위치의 절대 행 번호와 해당 파일 이름이 포함됩니다 eval. 이 배열은 funcsourcetrace및 와 길이는 동일 functrace하지만 funcsourcetrace라인과 파일이 정의 지점이 아닌 호출 지점이라는 점이 다르며 functrace모든 값이 함수 시작에 상대적인 것이 아니라 파일의 절대 라인 번호라는 점에서 다릅니다( 있습니다).

funcsourcetrace

이 배열에는 현재 실행 중인 함수, 소스 파일 및 (설정된 경우) 명령을 정의하는 지점의 파일 이름과 줄 번호가 포함됩니다 EVAL_LINENO. 줄 번호는 " " 또는 " "로 시작하는 줄입니다. 자동 로드된 함수의 경우 행 번호는 0으로 보고됩니다. 각 요소의 형식은 다음과 같습니다.evalfunction namename ()filename:lineno

기본 zsh 형식(파일에 함수 본문만 표시됨)의 파일에서 자동 로드되는 함수 또는 내장 함수 source또는 ' '에 의해 실행된 파일의 경우 추적 정보가 표시됩니다. 정의되어 있습니다. 함수를 로드할 때 소스 파일 이름은 절대 경로로 확인되고, 그렇지 않으면 해당 경로가 확인됩니다..filename:0

대부분의 사용자는 배열의 정보에 관심이 있을 것입니다 funcfiletrace.

funcstack

배열에는 함수 이름, 소스 파일 및 ( EVAL_LINENO설정된 경우) eval명령이 포함됩니다. 현재 실행 중입니다. 첫 번째 요소는 이 매개변수를 사용하는 함수의 이름입니다.

표준 쉘 배열을 zsh_eval_context사용하여 각 깊이에서 실행되는 쉘 구성의 유형을 결정할 수 있습니다. 그러나 순서가 반대이므로 마지막 항목이 가장 최근 항목이고 더 자세한 항목입니다(예: 최상위 항목 포함). 메인 셸 코드를 대화식으로 실행하거나 스크립트에서 실행하는 경우 $funcstack.

functrace

이 배열에는 현재 실행 중인 함수에 해당하는 호출자의 이름과 줄 번호가 포함됩니다. 각 요소의 형식은 입니다 name:lineno. 또한 소스 파일의 호출자는 source또는 ' ' 명령이 실행되는 지점입니다..

비교하다:

foo.bash:

#! /bin/bash
yelp() {
    caller 0
}

foo () {
    yelp
}

foo

foo.zsh:

#! /bin/zsh
yelp() {
    print -l -- $funcfiletrace - $funcsourcetrace - $funcstack - $functrace
}

foo () {
    yelp
}

foo

결과:

$ bash foo.bash
7 foo foo.bash

$ zsh foo.zsh
foo.zsh:7
foo.zsh:10
-
foo.zsh:2
foo.zsh:6
-
yelp
foo
-
foo:1
foo.zsh:10

따라서 해당 값은 ${funcfiletrace[1]}및 에 있습니다 ${funcstack[-1]}. 로 변경 yelp:

yelp() {
    print -- $funcfiletrace[1] $funcstack[-1]
}

출력은 다음과 같습니다

foo.zsh:7 foo

이것은 bash에 매우 가깝습니다.

7 foo foo.bash

답변2

기반으로무루의 대답, 두 가지 모두에서 작동하는 다음 기능을 구현했습니다 {ba,z}sh.

$ cat yelp
#!/bin/zsh
# Say the file, line number and optional message for debugging
# Inspired by bash's `caller` builtin
# Thanks to https://unix.stackexchange.com/a/453153/143394
function yelp () {
  # shellcheck disable=SC2154  # undeclared zsh variables in bash
  if [[ $BASH_VERSION ]]; then
    local file=${BASH_SOURCE[1]} func=${FUNCNAME[1]} line=${BASH_LINENO[0]}
  else  # zsh
    emulate -L zsh  # because we may be sourced by zsh `emulate bash -c`
    # $funcfiletrace has format:  file:line
    local file=${funcfiletrace[1]%:*} line=${funcfiletrace[1]##*:}
    local func=${funcstack[2]}
    [[ $func =~ / ]] && func=source  # $func may be filename. Use bash behaviour
  fi
  echo "${file##*/}:$func:$line $*" > /dev/tty
}

foo () { yelp; }
yelp
foo

출력은 다음과 같습니다

$ ./yelp
yelp::20 
yelp:foo:19

관련 정보