contexto de chamada da função em zsh: equivalente a bash 'caller'

7

No bash, eu posso escrever:

caller 0

e receba o contexto do responsável pela chamada :

  • Número da linha
  • Função
  • Nome do script

Isso é extremamente útil para depuração. Dado:

yelp () { caller 0; }

Eu posso escrever yelp para ver quais linhas de código estão sendo alcançadas.

Eu posso implementar caller 0 em bash como:

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

Como posso obter a mesma saída que caller 0 em zsh ?

    
por Tom Hale 03.07.2018 / 07:04

2 respostas

10

Eu não acho que haja um comando equivalente, mas alguma combinação dessas quatro variáveis de o módulo zsh / Parameter pode ser usado:

funcfiletrace

This array contains the absolute line numbers and corresponding file names for the point where the current function, sourced file, or (if EVAL_LINENO is set) eval command was called. The array is of the same length as funcsourcetrace and functrace, but differs from funcsourcetrace in that the line and file are the point of call, not the point of definition, and differs from functrace in that all values are absolute line numbers in files, rather than relative to the start of a function, if any.

funcsourcetrace

This array contains the file names and line numbers of the points where the functions, sourced files, and (if EVAL_LINENO is set) eval commands currently being executed were defined. The line number is the line where the ‘function name’ or ‘name ()’ started. In the case of an autoloaded function the line number is reported as zero. The format of each element is filename:lineno.

For functions autoloaded from a file in native zsh format, where only the body of the function occurs in the file, or for files that have been executed by the source or ‘.’ builtins, the trace information is shown as filename:0, since the entire file is the definition. The source file name is resolved to an absolute path when the function is loaded or the path to it otherwise resolved.

Most users will be interested in the information in the funcfiletrace array instead.

funcstack

This array contains the names of the functions, sourced files, and (if EVAL_LINENO is set) eval commands. currently being executed. The first element is the name of the function using the parameter.

The standard shell array zsh_eval_context can be used to determine the type of shell construct being executed at each depth: note, however, that is in the opposite order, with the most recent item last, and it is more detailed, for example including an entry for toplevel, the main shell code being executed either interactively or from a script, which is not present in $funcstack.

functrace

This array contains the names and line numbers of the callers corresponding to the functions currently being executed. The format of each element is name:lineno. Callers are also shown for sourced files; the caller is the point where the source or ‘.’ command was executed.

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

Os 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

Portanto, os valores correspondentes estão em ${funcfiletrace[1]} e ${funcstack[-1]} . Modificando yelp para:

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

A saída é:

foo.zsh:7 foo

que é bem próximo do bash

7 foo foo.bash
    
por 03.07.2018 / 07:42
3

Com base na resposta do muru , implementei a seguinte função que funciona em {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

A saída é:

$ ./yelp
yelp::20 
yelp:foo:19
    
por 03.07.2018 / 09:42