contesto di chiamata della funzione in zsh: equivalente di bash `caller`


8

In bash, posso scrivere:

caller 0

e ricevere il contesto del chiamante :

  • Numero di riga
  • Funzione
  • Nome dello script

Questo è estremamente utile per il debug. Dato:

yelp () { caller 0; }

Posso quindi scrivere yelpper vedere quali linee di codice vengono raggiunte.

Posso implementare caller 0in bashquanto:

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

Come posso ottenere lo stesso output di caller 0in zsh?

Risposte:


14

Non penso che ci sia un equivalente di comando incorporato , ma è possibile utilizzare una combinazione di queste quattro variabili dal modulo zsh / Parameter :

funcfiletrace

Questa matrice contiene i numeri di riga assoluti e i nomi dei file corrispondenti per il punto in cui EVAL_LINENOè evalstata chiamata la funzione corrente, il file di origine o il comando (se impostato) . L'array ha la stessa lunghezza di funcsourcetracee functrace, ma differisce dal fatto funcsourcetraceche la linea e il file sono il punto di chiamata, non il punto di definizione, e differisce dal fatto functraceche tutti i valori sono numeri di riga assoluti nei file, piuttosto che relativi al avvio di una funzione, se presente.

funcsourcetrace

Questa matrice contiene i nomi dei file e i numeri di riga dei punti in cui sono state definite le funzioni, i file di origine e i comandi (se EVAL_LINENOimpostati) evalattualmente in esecuzione. Il numero di riga è la riga da cui è iniziato " function name" o " name ()". Nel caso di una funzione caricata automaticamente, il numero di riga viene riportato come zero. Il formato di ogni elemento è filename:lineno.

Per le funzioni caricate automaticamente da un file nel formato zsh nativo, in cui solo il corpo della funzione si trova nel file, o per i file che sono stati eseguiti dai builtin sourceo ' .', le informazioni di traccia sono mostrate come filename:0, poiché l'intero file è il definizione. Il nome del file di origine viene risolto in un percorso assoluto quando la funzione viene caricata o il percorso viene risolto in altro modo.

La maggior parte degli utenti sarà invece interessata alle informazioni funcfiletracenell'array.

funcstack

Questa matrice contiene i nomi delle funzioni, i file di origine e i comandi (se EVAL_LINENOimpostati) eval. attualmente in esecuzione. Il primo elemento è il nome della funzione che utilizza il parametro

L'array di shell standard zsh_eval_contextpuò essere utilizzato per determinare il tipo di costrutto di shell che viene eseguito ad ogni profondità: nota, tuttavia, che è nell'ordine opposto, con l'ultimo elemento più recente, ed è più dettagliato, ad esempio includendo una voce per livello superiore, il codice della shell principale viene eseguito in modo interattivo o da uno script, che non è presente in $funcstack.

functrace

Questo array contiene i nomi e i numeri di riga dei chiamanti corrispondenti alle funzioni attualmente in esecuzione. Il formato di ogni elemento è name:lineno. I chiamanti vengono anche mostrati per i file provenienti; il chiamante è il punto in cui è stato eseguito il comando sourceo ' .'.

confrontando:

foo.bash:

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

foo () {
    yelp
}

foo

foo.zsh:

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

foo () {
    yelp
}

foo

I risultati:

$ 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

Quindi, i valori corrispondenti sono in ${funcfiletrace[1]}e ${funcstack[-1]}. Modifica yelpa:

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

L'output è:

foo.zsh:7 foo

che è abbastanza vicino a quello di Bash

7 foo foo.bash

3

Sulla base della risposta di Muru , ho implementato la seguente funzione che funziona in entrambi {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

L'output è:

$ ./yelp
yelp::20 
yelp:foo:19
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.