[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Incorrect alias expansion within command substitution

From: Robert Elz
Subject: Re: Incorrect alias expansion within command substitution
Date: Fri, 04 Feb 2022 02:52:34 +0700

    Date:        Thu, 03 Feb 2022 09:05:53 -0800
    From:        L A Walsh <bash@tlinx.org>
    Message-ID:  <61FC0B71.2080301@tlinx.org>

  | There is no way you can tell me that:
  | declare var='v'
  | declare -i ivar=1
  | are more clear than:
  | my var='v'
  | int ivar=1

I can, easily -- for the former if I am unsure what is going on, I can
just look in the bash man page to see what declare does, its options, and
so on.   I doubt that there is a man page for my or int (etc) - not your
usages anyway, so someone looking at your script has to work out that those
things are aliases, and not commands, and then having done all that, still
potentially look up the bash man page, to work out what declare actually does.

And despite what you think, scripts (or any code) are almost never (if they
last more than a day or two) just for you.  If they are useful at all,
eventually someone will inherit them, and have to make sense of what
you have written.   You might enjoy laying land mines for whoever that is,
personally, I don't think it is the right thing to do.

But assuming that you don't accept those arguments, which I am guessing
that you won't, aliases still aren't the right way (the way they're specified
and implemented means they have all kinds of weird properties, which you
might not be experiencing now, but will one day most likely).

You could instead use:

                local A=
                while [ $# -gt 0 ]
                        case "$1" in
                        int)    A="${A} -i";;
                        map)    A="${A} -A";;
                        array)  A="${A} -a";;
                        ....)   # as many more as you need
                        *)      break;;
                declare $A -- "$@"
        int() { my int "$@"; }
        array() { my array "$@"; }

Almost anything you can do with an alias, you can do with a function,
but with functions you can do so much more, like error checking with
error messages, etc, that aliases are simply incapable of (eg: in the
above, you could add a check to make sure that some variable name is
actually given, and if you want, depending upon the type, supply a
default value if there's no '=' given, ...)

About the only thing that aliases can do that functions cannot, is alter
the syntax (see Chet's "switch" command substitution example) - and apart
from people who are deliberately setting out to torture the implementation
to see what happens, that is never a rational thing to do.

Aliases are a botch.   They were invented in ashell (early 2nd half of the
1970's) as a shorthand mechanism, and vastly expanded (almost a whole
programming language) in csh (late 1970's) - all before shell functions were
invented.  Then they were great for interactive use (and still absurd for
scripts), now it is almost always better, for everything, to use a function
(bash even allows functions to be exported to the environment, not aliases
I don't think).

Your script type testing comments are all a red herring - while your
implementation might depend upon your type names, there's no reason it
needs to, if you always declare variables, then you can do as much type
checking as you desire, whatever the syntax used, just takes slightly
different code.   In fact, since bash's "declare -p" doesn't output
"int i" or anything like it, it would probably be easier if you were
simply using declare (explicitly) everywhere.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]