An annoying thing with the basic script wrapper approach is that completions might now break. You’d have to set up extra completions associated with the new aliased name.
fish solves this by allowing you to tell the shell that one function --wraps another. So e.g. this function from my dotfiles that marks it wraps fd and thus will pick up fd‘s completions. (You can see I’ve done that in some of the other functions there, too, if they’re truly wrapping something in a useful way).
I don’t remember the specifics, but I’m pretty sure that zsh could pull off something similar with comp def, too, via something like compdef alias=cmd, but two seconds of goofing off tells me my syntax isn’t quite right.
Aliases are a bad solution. Abbreviations in Fish have taken over 90% of my shell aliases, including even many of the git aliases I had. It’s just superior in every way.
It’s also better than the script in $PATH approach as they autocomplete and are more easily searchable in reverse history, plus you can template the command line and move the cursor where you want. Scripts or aliases can’t do that.
What I don’t use abbreviations for I use the script solution (rarely) or simple shell functions.
An abbreviation in fish expands after being typed, so you see the full command. There are some more advanced features such as templating, but I’m not experienced enough on that to speak too much about.
Thank you. You made me realize that that I need to use abbreviations way more often. I already do, but I still have some shell script in PATH that could just be abbreviations.
What I especially like about abbreviations is that when I copy&paste the outputs e.g. to document something or share instructions, my personal abbreviations are already expanded, so they don’t confuse other people.
for dead simple stuff like alias l=ls -la, I think using a function is overkill. That’s what most of my aliases look like. Anything else yeah, shell function or script file it is.
Aliases integrate more seamlessly with tab completion. You can write a custom tab completion for a wrapper shell function, but with an alias you don’t have to.
IMO you should prefer aliases, especially in zsh and fish because they transparently expand aliases when running tab completion which means that an alias g=git will still do proper tab completion. I don’t believe (though I haven’t verified) that a bare shell script will work the same way
I don’t really agree with the rationale, because it is missing the most important part of aliases (and functions for that matter), that they are easily discoverable.
Re “Easier to bypass”: You can easily create a small script that adjusts the path (removes your alias-path) and exec to the original command.
I think the article highlights the benefits of aliases well- I favor too much my own commands over aliases, and probably I could get some benefits from using aliases more.
My own trick on top is that I have a Python package with many commands, that I can install with pipx and get the commands on my path easily.
I use alias to fix typos. I have mkae, maek and amke aliased to make as I tend to make those typos. I also use alias to mask commands, like I have echo That command is not available for rm (I have a different command that’s longer to type that rm to ensure me some extra keystrokes to think about that I’m about to do).
Why would [you] write a script to call git from the script, with the exact same arguments, rather than just symlink git to g? If you change the arguments, that’s understandable.
This could totally work, just not with my personal workflow. If git isn’t where I expect, the symlink breaks. git’s path differs on my macOS and Linux machines. It also differs if I decide to install git from Homebrew instead of using the system version.
That’s fair, it had not occurred to me cross OS issues. I actually use git on mac from nix so it would be in an even more different place than yours (e.g. /Users/gabeio/.nix-profile/bin/git).
The one thing I can think of is that completion is just transparent. If the target command already has completion, you don’t have to wire up completion for the alias like you would have to for a function.
Zsh also has global aliases that can appear in any position, not just as the command word. For example, I alias \u.. to @{u}.. (a git range) as I use it frequently and the former is easier to type.
I generally use aliases over scripts, but one advantage of scripts is that they work “anywhere” in the command string, e.g. watch my-alias won’t work, whereas watch my-script does.
I don’t really care because in zsh you can use the -g flag in your alias to make it “global” (as another commenter mentioned), but i don’t know if this functionality is available in all shells.
An annoying thing with the basic script wrapper approach is that completions might now break. You’d have to set up extra completions associated with the new aliased name.
fishsolves this by allowing you to tell the shell that one function--wraps another. So e.g. this function from my dotfiles that marks it wrapsfdand thus will pick upfd‘s completions. (You can see I’ve done that in some of the other functions there, too, if they’re truly wrapping something in a useful way).I don’t remember the specifics, but I’m pretty sure that zsh could pull off something similar with comp def, too, via something like
compdef alias=cmd, but two seconds of goofing off tells me my syntax isn’t quite right.I do a mix of both of these, and I think that’s the best option.
There’s no reason not to use aliases for the simple things, and scripts for the less simple things. Best of both worlds.
Aliases are a bad solution. Abbreviations in Fish have taken over 90% of my shell aliases, including even many of the git aliases I had. It’s just superior in every way.
It’s also better than the script in $PATH approach as they autocomplete and are more easily searchable in reverse history, plus you can template the command line and move the cursor where you want. Scripts or aliases can’t do that.
What I don’t use abbreviations for I use the script solution (rarely) or simple shell functions.
What’s the difference, and what are the alternatives for those who don’t use fish?
An abbreviation in fish expands after being typed, so you see the full command. There are some more advanced features such as templating, but I’m not experienced enough on that to speak too much about.
That’s super cool! I have been using fish for a couple of years now and haven’t come across abbreviations yet – looks like it is time to give it a go!
As far as I know there are no alternatives in other shells. It’s something I’ve seen only in Fish.
The doc has some examples of its usefulness: https://fishshell.com/docs/current/cmds/abbr.html
You can set ZSH to tab expand aliases, and you can expand them with a keybind in bash as well. https://superuser.com/questions/1514569/how-to-expand-aliases-inline-in-zsh
I see. In comparison, I don’t really see why you’d say that “aliases are a bad solution”, then? Looks mostly like a matter of taste to me.
Thank you. You made me realize that that I need to use abbreviations way more often. I already do, but I still have some shell script in PATH that could just be abbreviations.
What I especially like about abbreviations is that when I copy&paste the outputs e.g. to document something or share instructions, my personal abbreviations are already expanded, so they don’t confuse other people.
Why does your shell not autocomplete$PATHbinary names?Never mind, I realised you meant it breaks the autocomplete of the binary’s arguments/flags/etc.
I tend to use shell functions, which have most of the listed benefits of both (though not the no-reloading one).
yeah. i never really got the point of aliases, when functions exist
my guess is that aliases were implemented first, and now they can’t be removed without breaking things for people
for dead simple stuff like
alias l=ls -la, I think using a function is overkill. That’s what most of my aliases look like. Anything else yeah, shell function or script file it is.Aliases integrate more seamlessly with tab completion. You can write a custom tab completion for a wrapper shell function, but with an alias you don’t have to.
In fish you can use the
--wrapsswitch tocompleteto inherit the existing completions (I think).I’d be Surprised if aliases are older than functions.
One significant difference is aliases don’t work in non-interactive contexts. Which avoids some footguns
Remember bash is a combination of interactive features from (t)csh with extended POSIX (k)sh. The C shell predates the Bourne shell.
The original Bourne shell did not have functions https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/man/man1/sh.1
But 2BSD csh did have aliases https://www.tuhs.org/cgi-bin/utree.pl?file=2BSD/man/csh.u
So I think aliases are older.
Therefore, I’m surprised. Thanks :)
I enable aliases in bash scripts, they’re good for some specific tricks.
My favorite is shell functions, but also I use fish, where variable scoping is more predictable.
fish also makes it super easy to add and edit functions with its
funcedandfuncsavecommandsYeah,
aliasis a wrapper around thoseIMO you should prefer aliases, especially in zsh and fish because they transparently expand aliases when running tab completion which means that an
alias g=gitwill still do proper tab completion. I don’t believe (though I haven’t verified) that a bare shell script will work the same wayI don’t really agree with the rationale, because it is missing the most important part of aliases (and functions for that matter), that they are easily discoverable.
Re “Easier to bypass”: You can easily create a small script that adjusts the path (removes your alias-path) and
execto the original command.I think the article highlights the benefits of aliases well- I favor too much my own commands over aliases, and probably I could get some benefits from using aliases more.
My own trick on top is that I have a Python package with many commands, that I can install with
pipxand get the commands on my path easily.I use
aliasto fix typos. I havemkae,maekandamkealiased tomakeas I tend to make those typos. I also usealiasto mask commands, like I haveecho That command is not availableforrm(I have a different command that’s longer to type thatrmto ensure me some extra keystrokes to think about that I’m about to do).Kudos also pointing out advantages of aliases!
It’s too common for people consider something the always superior option, ignoring any scenarios where that might not be true.
Why would [you] write a script to call git from the script, with the exact same arguments, rather than just symlink git to g? If you change the arguments, that’s understandable.
This could totally work, just not with my personal workflow. If
gitisn’t where I expect, the symlink breaks.git’s path differs on my macOS and Linux machines. It also differs if I decide to installgitfrom Homebrew instead of using the system version.That’s fair, it had not occurred to me cross OS issues. I actually use git on mac from nix so it would be in an even more different place than yours (e.g.
/Users/gabeio/.nix-profile/bin/git).It’s a minor thing, but re “No reloading; changes are picked up immediately,” I like the following aliases.
Overall, I agree with many of the commenters that aliases, functions, and scripts all have their uses.
what is the use for an alias? (what can an alias do that a function can’t)
The one thing I can think of is that completion is just transparent. If the target command already has completion, you don’t have to wire up completion for the alias like you would have to for a function.
Zsh also has global aliases that can appear in any position, not just as the command word. For example, I alias
\u..to@{u}..(a git range) as I use it frequently and the former is easier to type.…
I can’t comprehend why I haven’t thought of this yet.
I generally use aliases over scripts, but one advantage of scripts is that they work “anywhere” in the command string, e.g.
watch my-aliaswon’t work, whereaswatch my-scriptdoes.I don’t really care because in zsh you can use the
-gflag in your alias to make it “global” (as another commenter mentioned), but i don’t know if this functionality is available in all shells.