27

I have a bash function (or alias), for instance function install() {sudo apt-get install $@}. When running the command install dicelab, what I expect will actually be run is sudo apt-get install dicelab. Where can I see what was actually run by the shell? I would like to make sure that my more complicated aliases are working as expected.

3
  • Is that $@ part of your alias? Remember that aliases don't really support arguments, that will expand to the positional parameters (if any) of the context calling the alias. The usual way of running somealias some args works just by expanding the alias and leaving the arguments to follow it. If you actually want to be able to access the arguments, use a function, and quote the "$@"
    – ilkkachu
    May 4, 2017 at 7:54
  • My bad, I meant a bash function. I'll change it.
    – Alon Aviv
    May 4, 2017 at 8:06
  • 1
    @AlonAviv, Good. :) Still, best get in the habit of quoting that "$@", arguments with whitespace or glob characters will burn otherwise.
    – ilkkachu
    May 4, 2017 at 8:53

4 Answers 4

35

Use set -x in the shell.

$ alias hello='echo hello world!'
$ hello
hello world!
$ set -x
$ hello
+ echo hello world!
hello world!

Using set -x turns on the xtrace shell option (set +x turns it off) and should work in all Bourne-like shells, like bash, dash ksh93, pdksh and zsh. This prompts the shell to display the command that gets executed after alias expansions and variable expansions etc. has been performed.

The output will be on the standard error stream of the shell (just like the ordinary prompt) so it will not interfere with redirections of standard output, and it will be preceded by a prompt as defined by the PS4 shell variable (often +␣ by default).

Example with a few functions:

$ world () { echo "world"; }
$ hello () { echo "hello"; }
$ helloworld () { printf '%s %s!\n' "$(hello)" "$(world)"; }
$ helloworld
hello world!
$ set -x
$ helloworld
+ helloworld
++ hello
++ echo hello
++ world
++ echo world
+ printf '%s %s!\n' hello world
hello world!

With your specific example (with syntax corrected and added quotes):

$ install () { sudo apt-get install "$@"; }
$ set -x
$ install dicelab
+ install dicelab
+ sudo apt-get install dicelab
bash: sudo: command not found

(I don't use or have sudo on my system, so that error is expected.)

Note that there is a common utility already called install, so naming your function something else (aptin?) may be needed if you at some point want to use that utility.


Note that the trace output is debugging output. It is a representation of what the shell is doing while executing your command. The output that you see on the screen may not be suitable for shell input.

Also note that I was using bash above. Other shells may have another default trace prompt (zsh incorporates the string zsh and the current command's history number, for example) or may not "stack" the prompts up like bash does for nested calls.


I'm running I used to run with set -x in all my interactive shells by default. It's nice to see what actually got executed... but I've noticed that programmable tab completion etc. may cause unwanted trace output in some shells, and some shells are a bit verbose in their default trace output (e.g. zsh).

16

You could use shell-expand-line, which is bound to Control-Alt-e by default:

$ bind -p | grep shell-expand-line
"\e\C-e": shell-expand-line

Among other things, it will replace aliases in the current line with their definition so you can see a command you're still going to run. Example:

$ install dicelab # now press C-Alt-e
$ sudo apt-get install  dicelab # the above line will be replaced with this
3
6

Use builtin command type to see an alias or a function definition you are about to run

This solution doesn't require running the command

$ type ls
ls is aliased to `ls --color=auto -p'
$ type -a ls
ls is aliased to `ls --color=auto -p'
ls is /bin/ls

From help type: -a display all locations containing an executable named NAME; includes aliases, builtins, and functions, if and only if the `-p' option is not also used

$ function hello() { echo hello; }  # define function
$ type hello
hello is a function
hello () 
{ 
    echo hello
}
0

A simple approach for a specific alias is to try .

If you do ps -f, you will see the actual command adjacent to the process, not the name. You can verify that by defining the following alias:

alias doSleep="sleep 100"

then do

ps -f | grep "sleep"

and you will see

username   14303    2409  0 15:16 pts/0    00:00:00 sleep 100

Unfortunately, the command only shows the alias, so you couldn't use history to verify that the actual command ran; you could only search for the alias label in that case.

1
  • If you ran it with doSleep& and/or ^Z-ed out (which are the only ways you can see it in ps on the same terminal) then jobs (or jobs %id if you know/remember or guess the id) shows the expansion of an alias -- but not the contents of a function. which is the actual example in the question. Sep 23, 2022 at 4:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .