For example, if I have a
alias dbmigrate='rails db:migrate'
is there a mode or simple way to configure in Bash and Zsh so that when I type in the shell:
$ dbmigrate # press Enter
it will echo what the alias expands to before running it?
In bash, there are the alias-expand-line
and history-and-alias-expand-line
readline functions, but they aren't bound to any keys by default. You can bind them yourself -- example with Control-T
:
bind '"\C-T": history-and-alias-expand-line'
Trying to bind Enter
itself is would be messy, because not anytime you press Enter
you have the command executed (eg. not when it's an incomplete pipeline, etc).
There's also the DEBUG
trap, but determining whether the command was actually entered by the user (eg. not started from PROMPT_COMMAND
or from a command substitution in PS1
), and whether it was alias-expanded is going to be tricky; but if you're OK with it printing any command before being executed:
trap 'echo "> $BASH_COMMAND"' DEBUG
bash$ pwd
> pwd
In zsh, you can simply define a preexec
function which prints the expanded command if different from the one entered by the user:
preexec(){ [ $1 != $2 ] && print -r "> $2" }
zsh$ j
> jobs
Beware however that some alias + history tricks won't work properly if you force-expand the alias. For instance, I have an c
alias in bash to do calculations like c 3.17 * 4.2
, without having to escape the *
, (
, etc:
alias c='_c=$(fc -nl -0); bc -l <<<${_c#*c} #'
Once readline has expanded it, the current line from the history (the one returned by fc -nl -0
) will be the expanded, not the original command, and everything will fall apart.
Aliases are just simple substitutions. If you want to do something fancier, like print a message before running the command, you need something more powerful: a function. If you want the definition to look like an alias definition, you can define a function that defines a function.
function verbose_alias {
local name=${1%%=*} expansion=${1#*=}
eval "function $name {
printf >&2 '%s is an alias for %s\\n' \"$name\" \"$expansion\";
$expansion \"\$@\";
}"
}
verbose_alias dbmigrate='rails db:migrate'
POSIX requires the set
command to have this option
-x
The shell shall write to standard error a trace for each command after it expands the command and before it executes it. It is unspecified whether the command that turns tracing off is traced.
https://pubs.opengroup.org/onlinepubs/009604499/utilities/set.html
So you can just use set -x
or set -o xtrace
on any compatible shells. In bash you can see this in the man page:
-x
After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.
xtrace
Same as
-x
.
zsh also has a similar option for the set
builtin
XTRACE (
-x
, ksh:-x
)Print commands and their arguments as they are executed.
You can also specify the -x
option while executing scripts or commands
bash -x -c "echo This will be printed before running; ll"
bash -x script-to-be-debugged.sh
zsh -x -c "...; 3; md did-you-see-the-aliases"
zsh -x buggy-script.sh
Beware that it also expands the commands that are run before and after each prompt so it may be not desirable in many situations, for example when you use git
variables in your PS1. In my clean Ubuntu VM only the running command is printed out
See also What does set -x
do?
Another option is set -v
or set -o verbose
which doesn't expand the variables before printing
That kind of help is not available by default in bash.
The two related functions that are available by default are:
shopt -s histverify
If set, and readline is being used, the results of history substitution are not immediately passed to the shell parser. Instead, the resulting line is loaded into the readline editing buffer, allowing further modification.
Which addresses the part of an action when Enter
is pressed, but only with an history expansion on the command line. For example:
$ shopt -s histverify
$ echo "this is a test"
This is a test
$ echo !!
$ echo echo "this is a test" <---- expanded by the simple use of enter!!
shell-expand-line
shell-expand-line (M-C-e)
Expand the line as the shell does. This performs alias and history expansion as well as all of the shell word expansions. See HISTORY EXPANSION below for a description of history expansion.
This is exactly what you are asking for to be done, but the key to make it work is Ctrl-Alt-e
I am not aware of a solution that works with enter and executes shell-expand-line
, sorry.
fish
, you can useabbr
instead ofalias
. It will expand the abbreviated commands upon execution.which dbmigrate
. This will echo something likedbmigrate: aliased to rails db:migrate