1

For context, I'm using zsh. Every time I use locate, I want to pass the -i and -A flags.

Usually, if I can get away with it, I create an alias with the same name as the existing command to do this. But according to this question, aliases can't accept arguments, so I have to use a function instead. Usually I stop there because the idea of a function with the same name as a command feels wrong to me, though I can't say why.

I was about to finally create such a function when I had this thought: this is a common pattern for me, wanting to default flags for command; is there an easier way of going about it? Perhaps zsh provides a better solution to this problem?

That brought me to another thought: is it an anti-pattern to override an existing command? I've always done it because it allows me to skip an association in my head: e.g., "Why doesn't ll have a man page? Oh yeah: ll really means ls -la. I need to do man ls, not man ll. Etc."

To summarize:

  1. Is it alright/idiomatic to override an existing command with an alias/function?
  2. Does zsh or some other tool provide a more direct way to default flags for a specific command?

2 Answers2

3

I am really surprised by that other post you mentioned, as it can be very misleading. Just because an alias doesn't use parameters doesn't mean that aliases cannot set parameters. Of course you can put options in an alias, but it is just restricted, meaning, the alias is replaced in one place.

$ alias ls='ls -l'
$ ls 
# will run: ls -l
$ ls foo
# will run: ls -l foo

The problem that other question poses is if you want to add options to a alias that has a argument.

so if you had an alias:

$ alias movetotrash='mv  ~/Trash'
# no way to use inject anything inside 'mv' and '~/Trash'

So in your case

$ alias locate='locate -i -A'
# will expand to 'locate -i -A' and then whatever else you type.

As for your specific questions:

It is quite common for linux distributions to ship with default "options" via aliases, for example, ls frequently has a alias ls 'ls --color=auto' or for root login you might see alias mv 'mv -i'. So it can be considered a standard way of providing better defaults to users and uses the same name of the underlying binary. If a user doesn't want to use an alias and it is set in the standard environment, they can use unalias to unset the alias permanently, or when running a command using a backslash, such as \mv a b will prevent alias expansion for that execution (as does using the full path, like /usr/bin/mv a b)

I don't believe that zsh provides any extra capabilities in this area, and certainly nothing that would be a "standard". People often write wrapper shell scripts and sometimes shell functions. But for trivial software, alias is often the solution people use. If the program is complicated enough, it will usually gain an rc file for common user preferences.

I think one tool that tried to make options a bit easier was the popt library, which allowed users to create their own options to software, but the popt library isn't widely used, and I don't think it had the ability to set the default.

toppk
  • 657
  • I didn't expect to learn more than I asked, so thank you for taking the time to write that out. – Daniel Kaplan Sep 23 '22 at 23:35
  • I don't mean to offend, but I'm hesitant to mark this as the answer because, while this information is so useful it would've prevented my question in the first place, it doesn't directly answer the questions I had: if you could answer those questions I put at the bottom of the question, I'll mark this as accepted. Thanks – Daniel Kaplan Sep 23 '22 at 23:44
  • I have added some text to address the topics in your questions, but I cannot say that I've answered your questions. I will not be offended if you do not think I answered your question to your satisfaction, and maybe someone will come here with a comment or better answer! – toppk Sep 24 '22 at 02:08
0

Aliases that use the same name are almost the entire point of aliases.

An alias definition provides a string value that shall replace a command name when it is encountered

alias grep='grep --ignore-case --color=auto' works perfectly as a drop in replacement for grep.

Creating a function or a ~/bin/ script to replace a command will need you to reference the command directly.

function grep {
    grep --ignore-case --color=auto "${@}"
}

or

~/bin/grep:

grep --ignore-case --color=auto "${@}"

...will lock up in a recursive loop where the function or script calls itself endlessly while...

function grep {
    /bin/grep --ignore-case --color=auto "${@}"
}

or

~/bin/grep:

/bin/grep --ignore-case --color=auto "${@}"

...will not die the recursive death because they don't call themselves.

The only issue with aliases is that you can't insert arguments internally between 'default' arguments. You can with function and scripts...

function grep {
    /bin/grep ${1} --ignore-case --color=auto ${2} 
}

or

~/bin/grep:

/bin/grep ${1} --ignore-case --color=auto ${2}

...but it would get messy fast if you try to use the new version of the command expecting normal argument sequences.

SHawarden
  • 554
  • 2
    Use "$@" (i.e $@ inside double-quotes) instead of ${*}. Otherwise your functions will break on arguments which contain whitespace (e.g. a quoted string like 'this is one argument' or '/path/with/a few spaces/in it/'. Double-quote your positional parameters too - curly-braces, like ${1}, are not a substitute for quoting with either variables or positional parameters. See $VAR vs ${VAR} and to quote or not to quote, and Why does my shell script choke on whitespace or other special characters? – cas Sep 22 '22 at 08:39
  • 2
    @cas, In zsh, ${*} would not be split on whitespace (or whatever $IFS contains) like in other Bourne-like shells, but it's still wrong as it removes empty arguments and "$@" is the correct (and portable) form. – Stéphane Chazelas Sep 23 '22 at 07:49
  • 1
    You'd use grep() command grep -i --color=auto "$@" to invoke the external command (note that zsh's command predates POSIX' one and has different semantic, though equivalent in this case: in POSIX, command only bypasses functions, while in zsh, it calls the external command even when there's a builtin version, like yash's command -e). – Stéphane Chazelas Sep 23 '22 at 07:51
  • I am a little confused about the last example you've given, specifically the difference on both sides of the "or" line. On the top you have a function definition. On the bottom, I'm not sure how to interpret that. To me it looks like you are calling the custom script of grep, then you show coded using the absolute path of grep. It's kind of hard to know why I'm confused, but hopefully this is enough information to revise your answer – Daniel Kaplan Sep 23 '22 at 23:40
  • @DanielKaplan The latter is a script file in the user's bin folder being used to override whatever the main grep command is. – SHawarden Sep 27 '22 at 20:28
  • @cas The quotenon-quote links where very useful, thanks. Learn something new every day. I wasn't using the curly braces as quote substitutes. – SHawarden Sep 27 '22 at 20:32