contexto de chamada da função no zsh: equivalente ao bash `caller`

8

No bash, eu posso escrever:

caller 0

e receba o contexto do chamador :

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

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

yelp () { caller 0; }

Posso escrever yelppara ver quais linhas de código estão sendo alcançadas.

Posso implementar caller 0em bashcomo:

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

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

Tom Hale
fonte

Respostas:

14

Eu não acho que exista um comando interno equivalente, mas alguma combinação dessas quatro variáveis ​​do módulo zsh / Parameter pode ser usada:

funcfiletrace

Essa matriz contém os números absolutos de linha e os nomes de arquivos correspondentes para o ponto em que a função atual, o arquivo de origem ou o comando (se EVAL_LINENOdefinido) evalforam chamados. A matriz tem o mesmo comprimento que funcsourcetracee functrace, mas difere de funcsourcetraceque a linha e o arquivo são o ponto de chamada, não o ponto de definição e difere de functraceque todos os valores são números de linhas absolutos nos arquivos, em vez de relativos ao início de uma função, se houver.

funcsourcetrace

Essa matriz contém os nomes dos arquivos e os números de linha dos pontos em que foram definidas as funções, os arquivos originados e os comandos (se EVAL_LINENOdefinidos) evalatualmente em execução. O número da linha é a linha onde o ' function name' ou ' name ()' começou. No caso de uma função carregada automaticamente, o número da linha é relatado como zero. O formato de cada elemento é filename:lineno.

Para funções carregadas automaticamente de um arquivo no formato zsh nativo, em que apenas o corpo da função ocorre no arquivo ou para arquivos executados pelos componentes internos sourceou ' .', as informações de rastreio são mostradas como filename:0, já que o arquivo inteiro é o definição. O nome do arquivo de origem é resolvido para um caminho absoluto quando a função é carregada ou o caminho para ela é resolvido de outra forma.

A maioria dos usuários estará interessada nas informações da funcfiletracematriz.

funcstack

Essa matriz contém os nomes das funções, arquivos de origem e comandos (se EVAL_LINENOconfigurados) eval. sendo executado atualmente. O primeiro elemento é o nome da função usando o parâmetro

A matriz de shell padrão zsh_eval_contextpode ser usada para determinar o tipo de construção de shell que está sendo executada em cada profundidade: observe, porém, que está na ordem oposta, com o último item mais recente e é mais detalhado, por exemplo, incluindo uma entrada para nível superior, o código principal do shell sendo executado interativamente ou a partir de um script, que não está presente no $funcstack.

functrace

Essa matriz contém os nomes e os números de linha dos chamadores correspondentes às funções atualmente sendo executadas. O formato de cada elemento é name:lineno. Os chamadores também são mostrados para arquivos de origem; o chamador é o ponto em que o comando sourceou ' .' foi executado.

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 yelppara:

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

A saída é:

foo.zsh:7 foo

que é bem próximo do bash's

7 foo foo.bash
muru
fonte
3

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

A saída é:

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