{"id":68,"date":"2012-08-14T23:28:39","date_gmt":"2012-08-14T23:28:39","guid":{"rendered":"http:\/\/clayb.net\/blog\/?p=68"},"modified":"2012-10-23T02:39:41","modified_gmt":"2012-10-23T02:39:41","slug":"alias-does-not-work-as-expected-in-ksh-functions","status":"publish","type":"post","link":"https:\/\/clayb.net\/blog\/alias-does-not-work-as-expected-in-ksh-functions\/","title":{"rendered":"Alias does not work in KSH functions"},"content":{"rendered":"<h1>Alias does not work as expected in KSH functions<\/h1>\n<p>One will sometimes <a href=\"http:\/\/en.wikipedia.org\/w\/index.php?title=Alias_%28command%29&amp;oldid=506430935#History\">read<\/a> that a <tt>function<\/tt> is recommended over an <tt>alias<\/tt>, 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?<\/p>\n<p>Today, I ran into an aggravating situation. I found that a command which is set-up by sourcing a script with some <tt>alias<\/tt> commands in it. But, the script was failing to resolve the alias. I got <tt>alias_command: command not found<\/tt> instead of proper resolution. Even more aggravating, running the <tt>type<\/tt> built-in on the alias showed that it existed, and was set as expected, but to no success when calling it.<\/p>\n<p>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&#8217;Reilly book <a href=\"http:\/\/shop.oreilly.com\/product\/9780596005955.do\"><span style=\"text-decoration: underline;\">Classic Shell Scripting: Hidden Commands that Unlock the Power of Unix<\/span><\/a>, <a href=\"http:\/\/books.google.com\/books?id=jO-iKwPRX0QC&amp;lpg=PT188&amp;ots=xiZzwXcGuD&amp;dq=o'reilly%20classic%20shell%20scripting%20%22Figure%207-1.%20Steps%20in%20command-line%20processing%22&amp;pg=PT189#v=onepage&amp;q=o'reilly%20classic%20shell%20scripting%20%22Figure%207-1.%20Steps%20in%20command-line%20processing%22&amp;f=false\">Figure 7-1<\/a> 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?<\/p>\n<p>See below for a simple test-case to present the issues; and show some work-arounds.<\/p>\n<h2>Simple alias definition in a function<\/h2>\n<p><strong>This fails!<\/strong> This is the initial example of the failed behavior.<\/p>\n<pre class=\"brush:bash\">#!\/bin\/ksh\r\n\r\n# aliases do not seem to work in the function in which they are defined\r\nfunction alias_in_function_does_not_work {\r\n    print \"\\n\\nalias in a function does not work:\"\r\n    alias bar='ls'\r\n    type bar\r\n    bar\r\n}\r\n\r\nalias_in_function_does_not_work<\/pre>\n<pre>alias in a function does not work:\r\nbar is an alias for ls\r\n\/tmp\/t.sh[11]: alias_in_function_does_not_work[8]: bar: not found [No such file or directory]<\/pre>\n<h2>Simple alias definition in a function with eval<\/h2>\n<p><strong>This works!<\/strong> The extra <tt>eval<\/tt>in the following code block causes the shell to properly parse the alias.<\/p>\n<pre class=\"brush:bash\">#!\/bin\/ksh\r\n\r\n# aliases work in functions if preceeded with eval\r\nfunction alias_with_eval_works {\r\n    print \"\\n\\nalias in a function works with eval:\"\r\n    alias foobar='ls'\r\n    type foobar\r\n    eval foobar\r\n}\r\n\r\nalias_with_eval_works<\/pre>\n<pre>alias in a function works with eval:\r\nfoobar is an alias for ls\r\nfile<\/pre>\n<h2>Functions can replace aliases successfully<\/h2>\n<p><strong>This works!<\/strong> A function can replace an alias and perform (often) the same behavior. However, more thought is needed if you want to use <a href=\"https:\/\/mailman.research.att.com\/pipermail\/uwin-developers\/2003q2\/000747.html\">alias substitution<\/a> in clever ways.<\/p>\n<pre class=\"brush:bash\">#!\/bin\/ksh\r\n\r\n# a function being called by a function is okay\r\nfunction baz {\r\n    print \"functions work:\"\r\n    ls\r\n}\r\n\r\nfunction function_works {\r\n    print \"\\n\\nfunctions calling functions work:\"\r\n    baz\r\n}\r\n\r\nfunction_works<\/pre>\n<pre>functions calling functions work:\r\nfunctions work:\r\nfile<\/pre>\n<h2>Where the alias is defined matters<\/h2>\n<p><strong>I do not recommend this!<\/strong> 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!).<\/p>\n<pre class=\"brush:bash\">#!\/bin\/ksh\r\n\r\n# a pre-existing alias can be called only if\r\n# after the function definition in the script\r\nfunction pre_existing_alias_does_not_work {\r\n    print \"\\n\\nalias already defined does not yet work:\"\r\n    type foo\r\n    foo\r\n}\r\n\r\n# example showing aliases do not resolve in functions\r\nprint \"\\n\\nbare alias works:\"\r\nalias foo='ls'\r\ntype foo\r\nfoo\r\n\r\npre_existing_alias_does_not_work\r\n\r\n# a pre-existing alias can be called only if\r\n# after the function definition in the script\r\nfunction pre_existing_alias_now_works {\r\n    print \"\\n\\nalias already defined now works:\"\r\n    type foo\r\n    foo\r\n}\r\n\r\npre_existing_alias_now_works<\/pre>\n<pre>bare alias works:\r\nfoo is an alias for ls\r\nfile\r\n\r\nalias already defined does not yet work:\r\nfoo is an alias for ls\r\n\/tmp\/t.sh[16]: pre_existing_alias_does_not_work[7]: foo: not found [No such file or directory]\r\n\r\nalias already defined now works:\r\nfoo is an alias for ls\r\nfile<\/pre>\n<h2>Defining aliases in functions fails for other functions<\/h2>\n<p><strong>This fails!<\/strong> One can not create an alias in a function and then use it in another function, but one can in the main-line code.<\/p>\n<pre class=\"brush:plain\">#!\/bin\/ksh\r\n\r\nfunction setup_alias {\r\n    print \"\\n\\nalias setup...\"\r\n    alias foo='ls'\r\n}\r\n\r\n# a pre-existing alias can not be called if\r\n# the alias was defined in a function in the script\r\nfunction use_alias {\r\n    print \"\\n\\nalias already defined does not work:\"\r\n    type foo\r\n    foo\r\n}\r\n\r\nsetup_alias\r\nuse_alias\r\nprint \"\\n\\nbare alias works:\"\r\ntype foo\r\nfoo<\/pre>\n<pre>alias setup...\r\n\r\nalias already defined does not work:\r\nfoo is an alias for ls\r\n\/tmp\/t.sh[18]: use_alias[14]: foo: not found [No such file or directory]\r\n\r\nbare alias works:\r\nfoo is an alias for ls\r\nfile<\/pre>\n<h2>In summary&#8230;<\/h2>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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.<br \/>\n<a href=\"<?php echo get_permalink(); ?>&#8220;> Read More&#8230;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[],"_links":{"self":[{"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/posts\/68"}],"collection":[{"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/comments?post=68"}],"version-history":[{"count":0,"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/posts\/68\/revisions"}],"wp:attachment":[{"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/media?parent=68"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/categories?post=68"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/clayb.net\/blog\/wp-json\/wp\/v2\/tags?post=68"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}