contexto de llamada de la función en zsh: equivalente de bash `caller`

8

En bash, puedo escribir:

caller 0

y recibir el contexto de la persona que llama :

  • Número de línea
  • Función
  • Nombre del script

Esto es extremadamente útil para la depuración. Dado:

yelp () { caller 0; }

Entonces puedo escribir yelppara ver qué líneas de código se están alcanzando.

Puedo implementar caller 0en bashcomo:

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

¿Cómo puedo obtener el mismo resultado que caller 0en zsh?

Tom Hale
fuente

Respuestas:

14

No creo que haya un equivalente de comando incorporado , pero se puede usar alguna combinación de estas cuatro variables del módulo zsh / Parameter :

funcfiletrace

Esta matriz contiene los números de línea absolutos y los nombres de archivo correspondientes para el punto donde se llamó a la función actual, al archivo de origen o al comando (si EVAL_LINENOestá configurado) eval. La matriz tiene la misma longitud que funcsourcetracey functrace, pero difiere de funcsourcetraceque la línea y el archivo son el punto de llamada, no el punto de definición, y difiere de functraceque todos los valores son números de línea absolutos en los archivos, en lugar de en relación con el inicio de una función, si la hay.

funcsourcetrace

Esta matriz contiene los nombres de archivo y los números de línea de los puntos donde se definieron las funciones, los archivos de origen y (si EVAL_LINENOestá configurado) los evalcomandos que se ejecutan actualmente. El número de línea es la línea donde comenzó el ' function name' o ' name ()'. En el caso de una función con carga automática, el número de línea se informa como cero. El formato de cada elemento es filename:lineno.

Para funciones cargadas automáticamente desde un archivo en formato zsh nativo, donde solo el cuerpo de la función aparece en el archivo, o para archivos que han sido ejecutados por sourceo ' .' builtins, la información de rastreo se muestra como filename:0, ya que todo el archivo es el definición. El nombre del archivo fuente se resuelve en una ruta absoluta cuando se carga la función o la ruta se resuelve de otra manera.

La mayoría de los usuarios estarán interesados ​​en la información de la funcfiletracematriz.

funcstack

Esta matriz contiene los nombres de las funciones, los archivos de origen y los comandos (si EVAL_LINENOestá configurado) eval. actualmente en ejecución. El primer elemento es el nombre de la función que usa el parámetro.

La matriz de shell estándar zsh_eval_contextse puede utilizar para determinar el tipo de construcción de shell que se ejecuta en cada profundidad: tenga en cuenta, sin embargo, que está en el orden opuesto, con el último elemento más reciente, y es más detallado, por ejemplo, incluye una entrada para toplevel, el código de shell principal se ejecuta de forma interactiva o desde un script, que no está presente en $funcstack.

functrace

Esta matriz contiene los nombres y números de línea de los llamantes correspondientes a las funciones que se ejecutan actualmente. El formato de cada elemento es name:lineno. Las personas que llaman también se muestran para archivos de origen; la persona que llama es el punto donde se ejecutó el comando sourceo ' .'.

Comparando:

foo.bash:

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

foo () {
    yelp
}

foo

foo.zsh:

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

foo () {
    yelp
}

foo

Los resultados:

$ 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

Entonces, los valores correspondientes están en ${funcfiletrace[1]}y ${funcstack[-1]}. Modificando yelpa:

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

El resultado es:

foo.zsh:7 foo

que está bastante cerca de bash

7 foo foo.bash
muru
fuente
3

Basado en la respuesta de muru , implementé la siguiente función que funciona en ambos {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

El resultado es:

$ ./yelp
yelp::20 
yelp:foo:19
Tom Hale
fuente