Alias does not work as expected in KSH functions
One will sometimes read that a function is recommended over an alias, but it is not always obvious why. Certainly, one can do more in a more syntactically elegant way in a function than an alias; but why else?
Today, I ran into an aggravating situation. I found that a command which is set-up by sourcing a script with some alias commands in it. But, the script was failing to resolve the alias. I got alias_command: command not found instead of proper resolution. Even more aggravating, running the type built-in on the alias showed that it existed, and was set as expected, but to no success when calling it.
The problem seems to be that the alias is unavailable when the function is called. I do not quite understand why, but in the O’Reilly book Classic Shell Scripting: Hidden Commands that Unlock the Power of Unix, Figure 7-1 shows that alias resolution and where functions are looked up, happen at very different points in the parsing stack; it seems though that upon the eval loop for a calling a function should resolve the alias?
See below for a simple test-case to present the issues; and show some work-arounds.
Simple alias definition in a function
This fails! This is the initial example of the failed behavior.
#!/bin/ksh # aliases do not seem to work in the function in which they are defined function alias_in_function_does_not_work { print "\n\nalias in a function does not work:" alias bar='ls' type bar bar } alias_in_function_does_not_work
alias in a function does not work: bar is an alias for ls /tmp/t.sh[11]: alias_in_function_does_not_work[8]: bar: not found [No such file or directory]
Simple alias definition in a function with eval
This works! The extra evalin the following code block causes the shell to properly parse the alias.
#!/bin/ksh # aliases work in functions if preceeded with eval function alias_with_eval_works { print "\n\nalias in a function works with eval:" alias foobar='ls' type foobar eval foobar } alias_with_eval_works
alias in a function works with eval: foobar is an alias for ls file
Functions can replace aliases successfully
This works! A function can replace an alias and perform (often) the same behavior. However, more thought is needed if you want to use alias substitution in clever ways.
#!/bin/ksh # a function being called by a function is okay function baz { print "functions work:" ls } function function_works { print "\n\nfunctions calling functions work:" baz } function_works
functions calling functions work: functions work: file
Where the alias is defined matters
I do not recommend this! Here we show the code is indeed linearly parsed. A function can used an alias defined earlier in the code. (But this gets awfully convoluted quickly!).
#!/bin/ksh # a pre-existing alias can be called only if # after the function definition in the script function pre_existing_alias_does_not_work { print "\n\nalias already defined does not yet work:" type foo foo } # example showing aliases do not resolve in functions print "\n\nbare alias works:" alias foo='ls' type foo foo pre_existing_alias_does_not_work # a pre-existing alias can be called only if # after the function definition in the script function pre_existing_alias_now_works { print "\n\nalias already defined now works:" type foo foo } pre_existing_alias_now_works
bare alias works: foo is an alias for ls file alias already defined does not yet work: foo is an alias for ls /tmp/t.sh[16]: pre_existing_alias_does_not_work[7]: foo: not found [No such file or directory] alias already defined now works: foo is an alias for ls file
Defining aliases in functions fails for other functions
This fails! One can not create an alias in a function and then use it in another function, but one can in the main-line code.
#!/bin/ksh function setup_alias { print "\n\nalias setup..." alias foo='ls' } # a pre-existing alias can not be called if # the alias was defined in a function in the script function use_alias { print "\n\nalias already defined does not work:" type foo foo } setup_alias use_alias print "\n\nbare alias works:" type foo foo
alias setup... alias already defined does not work: foo is an alias for ls /tmp/t.sh[18]: use_alias[14]: foo: not found [No such file or directory] bare alias works: foo is an alias for ls file
In summary…
If you write shell scripts with functions, alias resolution really matters but may not be obvious as to how it is getting resolved or why. Certainly, if you have answers or resources to better explain this, please leave a comment.
ksh tokenizes dot files before processing them so define the alias before sourcing the function that uses it.
Thanks for this page, and thanks John Dough for the comment. I was loosing my hair over this.
Yes, If I source the alias first in a separate sourcing, and then I source my code containing functions, then my alias is available when the function runs.
Why would I use alias and not functions?
Because in an alias, I can use ‘$LINENO’ which gives me the line number when it is called.
So
sourcing the alias:
ALIAS ECHO=’echo $LINENO’
Anywhere in my code:
ECHO “Message”
-> displays the message with the line number. I use this for tracing…