Alias does not work in KSH functions

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.

2 Comments

  1. John Dough
    Posted October 17, 2013 at 9:53 pm | Permalink

    ksh tokenizes dot files before processing them so define the alias before sourcing the function that uses it.

  2. Posted April 7, 2016 at 11:28 am | Permalink

    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…

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*