In the previous posts we talked about which files you could use to customize your bash
environment.
There are (mainly) three customizations you can perform:
- environment variables
- aliases
- functions
This post will look at some useful aliases and functions.
bash
aliases
Note: bash
aliases are something completely different from Finder aliases. The closest shell equivalent for Finder alias files are symbolic links.
bash
aliases are basically text substitutions. For example a common alias
is to define:
alias ll="ls -l"
You can type this alias
definition directly into bash
but then the definition will only exist for that particular shell. When you open a new terminal window it will know nothing of this alias. If you want an alias to exist in all your shells (and usually you do), you need to add the above line to your .bash_profile
or .bashrc
. (Learn about the difference here.)
Whenever you modify the .bash_profile
or .bashrc
it will not automatically be loaded into any shell that is already open, you either have to close the Terminal window and open a new one or write
$ source ~/.bash_profile
(or ~/.bashrc
) to load the new settings.
Once you have set the alias, anytime you type ll
at the start of a command, bash
will replace it with ls -l
before executing. Since subsequent arguments are left alone they will just be picked up by the substituted ls
command, so if you type ll -a
bash will substitute that to ls -l -a
and it will work just your would expect.
You can make the alias
more complex if you want:
alias lll="ls -alhTOe@"
If you always want to use the long format of ls
, you can alias the ls
command itself:
alias ls="ls -l"
Then, when ever you type ls
it will be replaced with ls -l
. Note the lack of spaces around the ‘=
’, as usual when assigning values in bash.
Uncovering the alias
You can unset or delete an alias with the unalias
command:
$ unalias ls
This will return to the default ls
command (for this bash instance only).
Since alias substitution only happens at the beginning of the command, you can also bypass it once by starting the command line with a different character:
$ "ls" -S
$ \ls -S
Either way of typing this will use the original ls
command, avoiding substitution, just this once.
If you are unsure if a command has an alias or want to know what gets substituted, then you can have the alias definition printed with
$ alias ls
alias ls='ls -l'
$ alias lll
alias lll='ls -alhTOe@'
You can also list all defined aliases by running alias
without any arguments:
$ alias
alias ll='ls -l'
alias lll='ls -alhTOe@'
alias ls='ls -l'
Some Alias examples
Some users like to alias the potentially dangerous commands rm
, mv
and cp
with the -i
option, which forces the user to confirm when a file is going to be deleted or overwritten:
alias rm="rm -i"
alias mv="mv -i"
alias cp="cp -i"
Then if you do something that could destroy an existing file you will be prompted to confirm:
$ rm my_important_file
remove my_important_file?
You can still use \rm
to bypass the alias, if you believe you know what you are doing and want to avoid being prompted several times.
You can add short cuts to cd
to parent folders:
alias ..="cd .."
alias ...="cd ../.."
alias cd..="cd .."
Since alias substitution only takes place at the beginning of the command, you can still use ..
normally as an argument.
Note that the last alias cd..
is a substitution of a common typo. Since the output of the alias is not checked for further alias substitutions you cannot use alias cd..=..
to define it using the previous alias. Each alias must stand for itself.
You can also use aliases to make complex or hard to memorize commands easier to remember:
alias badge="tput bel"
The first command will play a system alert and set a ‘badge’ on the terminal application if it is in the background. This is useful to get notified of long running commands:
$ hdiutil convert image.sparseimage -format UDZO image.dmg; badge;
The substitution can be long and multiple commands can be separated by ;
alias dockspace="defaults write com.apple.dock persistent-apps -array-add '{\"tile-type\"=\"spacer-tile\";}'; killall Dock;"
The dockspace
alias uses this hack to add a spacer item to the dock.
We have seen earlier with the ll
alias that any text or arguments after the alias will just be added to the substituted command. We can use this to our advantage:
alias reveal='open -R'
alias xcode='open -a Xcode'
alias pacifist='open -a Pacifist'
All of these commands will require a file path as an ‘argument’ to work properly.
Functions: beyond the alias
While bash aliases are useful and easy to define, they have limitations. Aliases will only be replaced at the beginning of the command prompt. Also additional arguments will be appended after the replacement. If you need to insert additional arguments somewhere in the replacement, you cannot achieve that with aliases.
For example, to display the man page for ls
in the Preview application you need the following commands:
$ man -t ls | open -f -a "Preview"
If you wanted to alias this you would have to insert the arguments after man -t
and before the pipe. Since aliases, only substitute the beginning of the command, this will not work. we need to define a bash function:
function preman() {
man -t $@ | open -f -a "Preview"
}
Sometimes you will see bash functions defined without the function
keyword, but I prefer to use it since it makes the code more readable.
The $@
will be replaced with all the arguments passed into the function, so when use the function
$ preman ls
the argument ls
will be substituted where the $@
is.
You can also use the positional argument variables $1
, $2
, etc:
function recipe-open() {
open "$(autopkg info '$1' | grep 'Recipe file path' | cut -c 22-)"
}
Within functions the full power of bash
scripting is at your service. You can even call other scripting languages.
# prints the path of the front Finder window. Desktop if no window open
function pwdf () {
osascript <<EOS
tell application "Finder"
if (count of Finder windows) is 0 then
set dir to (desktop as alias)
else
set dir to ((target of Finder window 1) as alias)
end if
return POSIX path of dir
end tell
EOS
}
# changes directory to frontmost
alias cdf='pwdf; cd "$(pwdf)"'
The last alias cdf
has to be defined as an alias. Since a function or script could not change the directory for the current shell, you have to use alias substitution to get the cd
.
In general functions (and scripts) are more powerful and versatile than aliases, but aliases provide and easy and comparatively safe way to customize the your shell environment.
Putting it all together
Here is a sample .bash_profile
with many of the examples given here and in the previous article. You can use this as a starting point for your own bash configuration.
Shouldn’t it be Preview instead of “Preview” in the preman bash function ?
Since
Preview
contains no spaces, either will work. It is good practice to quote strings in scripts, even when not necessary.
When you copy/paste code you always have to check if the straight quotes were replaced with typographic or curly quotes, though. Shell scripts don’t like curly quotes. https://scriptingosx.com/2019/05/on-smart-quotes-and-terminal/
Hi love the blog man. I am trying to install a package of openssl on a Mac BigSur. Compiling and making the package is new to me but the post install script is a bit tricky. I thought of adding the following to If EUID is greater than 99 then alias openssl to the one i just installed in user local. You need this otherwise the system still chooses the the default old version in-spite-of-the-path-setting. If you want to leave the Mac system files alone, imo alias is the safest way to do that. The issue is the package will be deployed as root user but I only want the alias in the user space. That was my solution above. My issue is how do I write an install script to help me do this. It wont take my bash script as one… and throws and error. We use NoMAD.
My general recommendation is that installer pkgs should leave user space alone. There are too many edge cases, like multiple users, the user installing the pkg not being the user actually using the Mac, users that are created after you package has been installed, etc. These will break any process you might devise that affects user space.
You have two options (that I can think of) to put your new openssl binary in the users’ PATH:
1) install a symbolic link to your openssl in
/usr/local/bin
(this will override the pre-installed openssl)2) put a text file with a path to the folder containing your openssl in
/etc/paths.d
(this will not override the existing openssl)(details here: https://scriptingosx.com/2017/05/where-paths-come-from/)
With these options, all users on that system will get the new tool in the PATH for the interactive shell.