contexte d'appel de la fonction dans zsh: équivalent de bash `caller`

8

En bash, je peux écrire:

caller 0

et recevez le contexte de l' appelant :

  • Numéro de ligne
  • Une fonction
  • Nom du script

Ceci est extrêmement utile pour le débogage. Donné:

yelp () { caller 0; }

Je peux ensuite écrire yelppour voir quelles lignes de code sont atteintes.

Je peux implémenter caller 0en bashtant que:

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

Comment puis - je obtenir le même résultat que caller 0dans zsh?

Tom Hale
la source

Réponses:

14

Je ne pense pas qu'il y ait un équivalent de commande intégrée , mais une combinaison de ces quatre variables du module zsh / Parameter peut être utilisée:

funcfiletrace

Ce tableau contient les numéros de ligne absolus et les noms de fichiers correspondants pour le point où la fonction actuelle, le fichier d'origine ou (si elle EVAL_LINENOest définie) a evalété appelée. Le tableau est de la même longueur que funcsourcetraceet functrace, mais diffère de funcsourcetracepar le fait que la ligne et le fichier sont le point d'appel, pas le point de définition, et diffère par le fait functraceque toutes les valeurs sont des numéros de ligne absolus dans les fichiers, plutôt que par rapport à la début d'une fonction, le cas échéant.

funcsourcetrace

Ce tableau contient les noms de fichiers et les numéros de ligne des points où les fonctions, les fichiers d'origine et (si EVAL_LINENOdéfini) les eval commandes en cours d'exécution ont été définis. Le numéro de ligne est la ligne où le ' function name' ou le ' name ()' a commencé. Dans le cas d'une fonction à chargement automatique, le numéro de ligne est signalé comme zéro. Le format de chaque élément est filename:lineno.

Pour les fonctions chargées automatiquement à partir d'un fichier au format zsh natif, où seul le corps de la fonction apparaît dans le fichier, ou pour les fichiers qui ont été exécutés par les commandes internes sourceou ' .', les informations de trace sont affichées comme filename:0, puisque le fichier entier est le définition. Le nom du fichier source est résolu en un chemin absolu lorsque la fonction est chargée ou le chemin d'accès résolu autrement.

La plupart des utilisateurs seront plutôt intéressés par les informations du funcfiletracetableau.

funcstack

Ce tableau contient les noms des fonctions, des fichiers sources et (si EVAL_LINENOdéfini) des evalcommandes. en cours d'exécution. Le premier élément est le nom de la fonction utilisant le paramètre.

Le tableau de shell standard zsh_eval_contextpeut être utilisé pour déterminer le type de construction de shell exécuté à chaque profondeur: notez cependant que c'est dans l'ordre inverse, avec le dernier élément en dernier, et il est plus détaillé, par exemple en incluant une entrée pour toplevel, le code shell principal étant exécuté de manière interactive ou à partir d'un script, qui n'est pas présent dans $funcstack.

functrace

Ce tableau contient les noms et numéros de ligne des appelants correspondant aux fonctions en cours d'exécution. Le format de chaque élément est name:lineno. Les appelants sont également affichés pour les fichiers d'origine; l'appelant est le point où la commande sourceou ' .' a été exécutée.

Comparant:

foo.bash:

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

foo () {
    yelp
}

foo

foo.zsh:

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

foo () {
    yelp
}

foo

Les resultats:

$ 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

Ainsi, les valeurs correspondantes sont dans ${funcfiletrace[1]}et ${funcstack[-1]}. Modification yelpà:

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

La sortie est:

foo.zsh:7 foo

qui est assez proche de bash

7 foo foo.bash
muru
la source
3

Sur la base de la réponse de muru , j'ai implémenté la fonction suivante qui fonctionne dans les deux {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

La sortie est:

$ ./yelp
yelp::20 
yelp:foo:19
Tom Hale
la source