6

When I use the shell builtin time, I can pass any command I would pass to the shell without time. But when I use the external /usr/bin/time, I cannot pass a shell alias, because /usr/bin/time is naturally not aware of those:

$ /usr/bin/time ll
/usr/bin/time: cannot run ll: No such file or directory

How can I convince the shell to expand the alias for ll before passing it on to /usr/bin/time? Parsing the output of alias ll is tricky, in particular since the definition of the alias contains other aliases.


My reason for using /usr/bin/time is to measure peak memory usage.

gerrit
  • 3,457
  • 6
  • 25
  • 41

2 Answers2

3

You can define an alias for /usr/bin/time as:

alias 'ubtime=/usr/bin/time '

Or

alias 'ubtime=command time '

if you don't want to hard code the path to the time executable.

The trick is in the trailing space in the alias definition that tells the shell that aliases must be substituted after that alias so that

ubtime ll

Will actually be expanded to

/usr/bin/time ls -l

(assuming ll is an alias to ls -l).

In any case, /usr/bin/time being a standalone executable, it cannot time pipelines or compound commands or functions or shell builtins, so it cannot time the expansion of arbitrary aliases.

If the reason for using /usr/bin/time is because you prefer its default output format over the one for the time keywork, note that in many shells, the format can be modified. For instance, in zsh:

$ TIMEFMT=$'\e[31;1m%J\e[m: U:%U S:%S (%*E total) [avgtext:%X avgdata:%D maxmem:%M]'
$ time ls -l | head -n1
total 288072444
ls -l: U:0.00s S:0.01s (0.017 total) [avgtext:0 avgdata:0 maxmem:3]
head -n1: U:0.00s S:0.00s (0.015 total) [avgtext:0 avgdata:0 maxmem:3]

(the \e[31;1m for coloured (bold red) output).

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • Ah ok, this seems to work even for nested aliases, but still not if functions are involved or if the expanded alias does not start with a binary name. – rudimeier Sep 27 '16 at 14:26
  • This appears to expand a single 'layer', thus it works if `ll` itself does not contain other aliases. My `ll` alias is actually `alias ll='LANG='\''en_GB.UTF8'\'' l --full-time --almost-all --reverse --sort=time --time-style='\''+%9A %Y-%m-%d %H:%M:%S'\'''`, and `alias l='ls --format=long'`. The command works for my `l` but not for my `ll`. – gerrit Sep 27 '16 at 14:28
  • @gerrit, that's because of your `LANG=...`. That gets expanded to `/usr/bin/time LANG=... ls ...` as expected (so it works), but `/usr/bin/time` doesn't know what to do about that `LANG=...`. It tries to run it as a command. – Stéphane Chazelas Sep 27 '16 at 14:37
  • Well, actually this is the correct answer to the question: "How to expand the alias before passing it on to /usr/bin/time?" Unfortunately /usr/bin/time can't work on arbitrary alias expansions at all. – rudimeier Sep 27 '16 at 14:42
  • @rudimeter, see also my edit to make the `time` keyword output more information like `/usr/bin/time` (at least the GNU one) does. – Stéphane Chazelas Sep 27 '16 at 14:45
  • @StéphaneChazelas I see. I also see that there is one caveat here, namely that it doesn't work if passing arguments to `/usr/bin/time`, they would have to be part of the alias (I was actually running `\time -v`). – gerrit Sep 27 '16 at 14:48
  • If you would add something like the last 3 lines of my other answer I would delete my one. – rudimeier Sep 28 '16 at 23:32
0

This may work in bash:

/usr/bin/time  $(alias "ll" | sed "s/^alias [^=]*='\(.*\)'/\1/")

but not yet fully safe for arbitrary aliases, regarding spaces, escaped characters, nested aliases and functions etc.

I guess there is no non-ugly solution possible. That's why shells have a built-in time. Even if alias expansion would be easier, the next problem would be how to time functions. Note that aliases may even use shell functions.

If your aliases are defined in bash's configuration files and if you don't care about the timed overhead you could try

/usr/bin/time bash -l -i -c "ll"
rudimeier
  • 9,967
  • 2
  • 33
  • 45
  • This doesn't expand nested aliases; my alias `ll` refers to yet other aliases. I see that this is more complex than I thought. `\time bash --login -c ll` does not work either. – gerrit Sep 27 '16 at 13:56
  • 1
    The `-i` flag works where I thought `--login` would! I see that bash does not inherit aliases, but for my present use case it is good enough. – gerrit Sep 27 '16 at 14:02
  • 1
    -i (interactive) is required for `shopt expand_aliases` being enabled. --login may be required too to read all config files (~/.profile). I've added both to the answer. – rudimeier Sep 27 '16 at 14:10