zshでの関数の呼び出しコンテキスト:bash `caller`と同等


8

bashでは、私は書くことができます:

caller 0

呼び出し元のコンテキストを受け取ります:

  • 行番号
  • 関数
  • スクリプト名

これはデバッグに非常に役立ちます。与えられた:

yelp () { caller 0; }

次に、yelpどのコード行に到達しているかを確認するために書き込むことができます。

私が実装することができますcaller 0bashのように:

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

どのように私は同じ出力を得ることができますcaller 0ではzsh

回答:


14

同等の組み込みコマンドはないと思いますが、zsh / Parameterモジュールからのこれらの4つの変数のいくつかの組み合わせを使用できます。

funcfiletrace

この配列には、現在の関数、ソースファイル、または(EVAL_LINENO設定されている場合)evalコマンドが呼び出されたポイントの絶対行番号と対応するファイル名 が含まれます。配列は同じ長さであるfuncsourcetracefunctrace、しかしと異なる funcsourcetraceでは、ラインとファイルから呼び出し、定義ではない点、及び異なる点であることをfunctraceすべての値は、絶対行番号がファイルにあることに対してではなく、中関数の開始(ある場合)。

funcsourcetrace

この配列には、 現在実行されている関数、ソースファイル、および(EVAL_LINENO設定evalされている場合)コマンドが定義されたポイントのファイル名と行番号が含まれています。行番号は、 ' function name'または ' name ()'が開始した行です。自動ロードされた関数の場合、行番号はゼロとして報告されます。各要素の形式は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

3

muruの答えに基づいて、私は両方で機能する次の関数を実装しました{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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.