2

Inside a function, how can I get the file name of whatever script called that function?

Via prompt expansion, %x provides the name of the file that defines the function. %N provides the function name. How do I get the name of the file that called the function?

This would be useful to report the runtime of each of my startup scripts, e.g.:

~/.zshenv:

function start_timer() {
  start_time=$(date +%s.%N)
}
function stop_timer() {
  stop_time=$(date +%s.%N)
  elapsed_time=$((stop_time-start_time))
  echo "$SCRIPTNAME took $elapsed_time seconds"
}
start_timer
# initialize env...
end_timer # "~/.zshenv took 0 seconds"

~/.zshrc:

start_timer
# initialize interactive shell...
end_timer # "~/.zshrc took 2 seconds"

~/.zlogin:

start_timer
# initialize login shell...
end_timer # "~/.zlogin took 2 seconds"
mgiuffrida
  • 3,205
  • 1
  • 23
  • 24
  • Here is a [very similar question](http://stackoverflow.com/questions/9901210) but also no real solution. – Lucas Apr 15 '16 at 10:12

2 Answers2

5

At least in zsh 5.7.1, the ZSH_ARGZERO variable will report the name of the current script, even if the function within which it is called is different:

$ cat foo
function a_function_in_foo {
    echo "ZSH_ARGZERO=$ZSH_ARGZERO"
}
$ cat bar
source foo
a_function_in_foo
$ zsh bar
ZSH_ARGZERO=bar

It is documented at http://zsh.sourceforge.net/Doc/Release/Parameters.html as

ZSH_ARGZERO

If zsh was invoked to run a script, this is the name of the script. Otherwise, it is the name used to invoke the current shell. This is the same as the value of $0 when the POSIX_ARGZERO option is set, but is always available.

bschlueter
  • 3,422
  • 27
  • 45
  • On zsh 5.8 with Debian: `$ZSH_ARGZERO` in a function echos `zsh` when script is called from a `terminal` and `~/.vscode/extensions/rogalmic.zsh-debug-0.1.3/zshdb_dir/zshdb` when run from `vscode` with `zsh-debug` extension. – Timo May 05 '21 at 06:19
1

You could pass the name as a parameter.

~/.zshenv:

function start_timer() {
  echo "File: `basename $@`"             # <----
  start_time=$(date +%s.%N)
}

~/.zshrc:

start_timer $0                           # <----
# initialize interactive shell...
end_timer # "~/.zshrc took 2 seconds"

basename only strips everything before the last slash in case you only want to show the file name.

My test:

 File: aliases.zsh
 took 0.0018649101257324219 seconds

And - if you call scripts by yourself you also can use time as a prefix command to print their execution times.

$ time touch x
touch x  0.00s user 0.00s system 7% cpu 0.019 total
pommes
  • 171
  • 1
  • 4
  • When sourced on initialization by zsh, `$0` is simply `zsh` in every startup file. It would work if I passed the script name to the function directly, like `end_time ${(%):-%x}`, but you can see why I'd rather not use that at each invocation :) – mgiuffrida Feb 28 '16 at 04:00