Apple’s heavy hand is forcing adoption of POSIX and even switch to Python, to get away from Bashisms
Overview
- TL;DR Summary
- Among shells
- Why the disruption?
- Zsh is already in macOS
- Why Z shell is better than Bash
- Script Bashisms break in Zsh
- Z Shell plug-ins
- Z shell Prompts
- Z shell themes
- Bashisms against portability
- Plugins
- Change default shell back to bash
- Why not Fish?
- Why not jump temporarily to Python?
- Video Tutorials
- Other Resources
- Dotfiles for Zsh
- More on OSX
At its developer conference on June 4, 2019, Apple stated that, beginning with the Fall 2019 Catalina version of macOS, Z shell (zsh) would replace Bash as the default shell command language interpreter.
This article presents a deep yet hopefully succinct guided tour through Z shell usage and issues.
NOTE: Content here are my personal opinions, and not intended to represent any employer (past or present). “PROTIP:” here highlight information I haven’t seen elsewhere on the internet because it is hard-won, little-know but significant facts based on my personal research and experience.
TL;DR Summary
BTW Shells are a command line interface (CLI) that allows users to interact with the computer’s operating system by typing rather than moving a mouse on a GUI (Graphical User Interface).
PROTIP: Ignore fake news clickbait articles such as “Upcoming MacOS Catalina to Ditch Bash in Favour of Zsh” (from InfoQ), which is technically incorrect. The Apple announcement is about the default. After the change goes into effect, Bash will still be installed and you can still change the default back to Bash.
- Apple already ships Z shell with macOS (as well as the
sh
shell interpreter) along withbash
. But prompts are not compatible. - The version of zsh is likely obsolete. So install latest (parallel) version of Zsh and set
.zshrc
. - Execute zsh temporarily or as default
- zsh is better than bash/sh in several aspects
- Bash scripts break in Zsh (due to “bashisms”)
- Bashisms in bash scripts break in zsh, so existing bash scripts need to be migrated and tested
- Apple’s disruption opens up a discussion about compatibility of script commands across platforms and POSIX.
- Change the default shell back to bash
- Switch to an alternative shell replacement FISH?
- Exit to Python and back is perhaps the ultimate solution for cross-platform compatibile automation
Among shells
First, open a Terminal on your macOS machine (on Mojave or whatever version).
In fact, several shell programs are installed with macOS:
-
Get a list of shells allowed:*
cat /etc/shells
The response (on macOS Catalina) is:
# List of acceptable shells for chpass(1). # Ftpd will not allow users to connect who are not using # one of these shells. /bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh /usr/local/bin/bash
-
PROTIP: The predecessor Bourne Shell can still be invoked by the
sh
command.sh --version
The response on macOS Mojave thru Monterey:
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) Copyright (C) 2007 Free Software Foundation, Inc.
Why the disruption?
-
Obtain the version metadata:
bash --version
The response on a machine running macOS Catalina and Mojave and Monterey:
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18) Copyright (C) 2007 Free Software Foundation, Inc.
The “GNU” in the response reminds us that
bash
(named as a contraction of “Bourne-Again Shell”), replaces the Bourne Shell by adding “Bashisms”.* See https://en.wikipedia.org/wiki/Bash_(Unix_shell)The Verge notes that “Apple is stuck using version 3.2 of bash that has been licensed under GPLv2, as newer versions are licensed under GPLv3. Apple has kept clear of using GPLv3 packages in macOS as the license is generally more restrictive to companies like Apple that sign their own code and it includes explicit patent grants, too.[sic]”
A big reason to upgrade to Bash 4.0 (introduced February 2009) and Bash 5.0+ are associative arrays.
“All of this probably motivated by a desire to get away from GPL to MIT.” based on these statistics.
Zsh is already in macOS
-
Identify the version of zsh installed while on Mojave or earlier:
zsh --version
The response if you are at Catalina version:
zsh 5.7.1 (x86_64-apple-darwin19.0)
The response if you are at Mojave version:
zsh 5.0.5 (x86_64-apple-darwin14.0)
The response if you are at Monterey version:
zsh 5.8 (x86_64-apple-darwin18.7.0)
Notice no “GNU”.
PROTIP: Wikipedia says “Zsh is an extended Bourne shell with a large number of improvements, including some features of Bash, ksh, and tcsh.” (Korn shell). tcsh (“tee shell”) is the native root shell for BSD-based systems such as FreeBSD, which early versions of MacOS is based. OS X switched from tcsh to bash in version 10.3. tcsh is based on csh, the C-shell.
See Comparison of command shells on Wikipedia
macOS does not have latest Zsh
PROTIP: The version of zsh from Apple is likely not the latest because Apple does not automatically update it (like modern browsers do).
-
The latest version of Zsh available is listed in the Zsh website’s News page at
http://zsh.sourceforge.net/News
At time of writing (under macOS Monterey), it’s 5.8
PROTIP: Zshell has been around so long that its source code repository is still on Sourceforge since its initial release in 1990, at
https://sourceforge.net/p/zsh/code/ci/master/tree/ and
https://sourceforge.net/projects/zsh/filesInstall latest Z Shell (zsh) using Homebrew
PROTIP: Since one should not overwrite Apple’s stuff, upgrading requires installation of the latest version as if it did not already exist.
-
PROTIP: Z shell is also called zsh because of the Homebrew command to install it on macOS:https://github.com/robbyrussell/oh-my-zsh/wiki/themes
brew install zsh zsh-completions
NOTE: Ignore advice to add
-without-etcdir
to disable the reading of Zsh rc files in /etc, which is obsolete since 2018.BTW, On an Ubuntu system the install command is similar:
sudo apt install zsh
The response when run under macOS Mojave:
==> Installing dependencies for zsh: pcre ==> Installing zsh dependency: pcre ==> Downloading https://homebrew.bintray.com/bottles/pcre-8.43.mojave.bottle.tar ==> Downloading from https://akamai.bintray.com/08/08e7414a7641d1e184c936537ff67 ######################################################################## 100.0% ==> Pouring pcre-8.43.mojave.bottle.tar.gz 🍺 /usr/local/Cellar/pcre/8.43: 204 files, 5.5MB ==> Installing zsh ==> Downloading https://homebrew.bintray.com/bottles/zsh-5.7.1.mojave.bottle.tar ==> Downloading from https://akamai.bintray.com/79/793d87f67e64a5e01dfdea890af21 ######################################################################## 100.0% ==> Pouring zsh-5.7.1.mojave.bottle.tar.gz 🍺 /usr/local/Cellar/zsh/5.7.1: 1,515 files, 13.3MB
PROTIP: Notice that the “mojave” in the message above means that the installation needs to be repeated with each new version of Apple macOS.
PROTIP: Notice the “To activate these completions, add the following to your .zshrc:”
-
Get information about what was installed:
brew info zsh
The response at time of writing:
zsh: stable 5.8.1 (bottled), HEAD UNIX shell (command interpreter) https://www.zsh.org/ /usr/local/Cellar/zsh/5.8.1 (1,531 files, 14.7MB) * Poured from bottle on 2022-03-26 at 12:59:10 From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/zsh.rb ==> Dependencies Required: ncurses ✔, pcre ✔ ==> Options --HEAD Install HEAD version ==> Analytics install: 49,943 (30 days), 139,410 (90 days), 426,918 (365 days) install-on-request: 47,643 (30 days), 130,359 (90 days), 393,065 (365 days) build-error: 2 (30 days)
Previously:
Poured from bottle on 2019-06-05 at 14:43:05 /usr/local/Cellar/zsh/5.7.1 (1,515 files, 13.3MB) * install: 42,894 (30 days), 131,013 (90 days), 641,092 (365 days) install_on_request: 41,019 (30 days), 124,257 (90 days), 587,940 (365 days) build_error: 0 (30 days)
-
Confirm location of installation:
ls -la /usr/local/bin/zs*
The response:
lrwxr-xr-x 1 wilsonmar admin 27 Jun 5 14:43 /usr/local/bin/zsh -> ../Cellar/zsh/5.7.1/bin/zsh lrwxr-xr-x 1 wilsonmar admin 33 Jun 5 14:43 /usr/local/bin/zsh-5.7.1 -> ../Cellar/zsh/5.7.1/bin/zsh-5.7.1
Install Zsh Completions
-
Run
brew install zsh zsh-completions
The response at time of writing:
==> Downloading https://github.com/zsh-users/zsh-completions/archive/0.30.0.tar. ==> Downloading from https://codeload.github.com/zsh-users/zsh-completions/tar.g ######################################################################## 100.0% ==> Caveats To activate these completions, add the following to your .zshrc: if type brew &>/dev/null; then FPATH=$(brew --prefix)/share/zsh-completions:$FPATH autoload -Uz compinit compinit fi You may also need to force rebuild zcompdump: rm -f ~/.zcompdump; compinit Additionally, if you receive "zsh compinit: insecure directories" warnings when attempting to load these completions, you may need to run this: chmod -R go-w '/opt/homebrew/share/zsh'
Previously:
fpath=(/usr/local/share/zsh-completions $fpath) You may also need to force rebuild `zcompdump`: rm -f ~/.zcompdump; compinit Additionally, if you receive "zsh compinit: insecure directories" warnings when attempting to load these completions, you may need to run this: chmod go-w '/usr/local/share' ==> Summary 🍺 /usr/local/Cellar/zsh-completions/0.30.0: 133 files, 980.2KB, built in 8 seconds
VSCode Config for Zsh
To have VSCode recognize Zsh files:
-
Highlight and copy this line below
"terminal.integrated.shell.osx": "/bin/zsh"
- Press command + , (comma) to open VSCode settings.
- Type “Bash” in the search box.
- In the expanded “Features” and “Terminal” menu item,
- Click “Edit in settings.json” Within “Terminal > Integrated > Profiles: osX” to open another tab.
- Press command+, (comma) to go to the bottom of the file.
- Type a comma at the end of the last entry and press Enter to create a new blank line.
-
Click command+V to paste above the “}” last line of the file.
- Close the Settings and settings.json tabs.
-
Restart VSCode.
Config for Zsh
On Linux startup, zsh runs configuration file
/etc/zshenv
by default.Global Order: .zshenv → .zprofile → .zshrc → .zlogin → .zlogout
On macOS, zsh looks for configuration files in
$HOME
folder (/usr/username).- .zshenv is always sourced (run) during login and on all invocations of the Terminal shell, unless the -f option is set. If you want to de-clutter your $HOME directory by specifying an alternative location for other zsh configuration files in a subfolder, define in
~/.zshenv
a variable such as
ZDOTDIR=$HOME/.config/zsh
~/.zshenv
should contain commands to set the $PATH where the OS looks for executables. This file is also the place to define$EDITOR
,$PAGER
, and$ZDOTDIR
. It should not contain commands that produce output or assume the shell is attached to a tty.When you type command
zsh
and press enter in the command prompt or when you open a new Terminal tab, you invoke an interactive non-login shell.A script called by launchd runs under a non-interactive non-login shell, so neither .zprofile nor .zshrc are loaded.
-
.zprofile is loaded only once at login time. It is an alternative to
.zlogin
for ksh fans. They both set the environment for login shells. The two are not intended to be used together, although this could be done if desired. -
.zshrc is sourced in interactive sub-shells. It should contain commands to set up keyboard aliases, functions, options, key bindings, etc. needed for interactive work. PROTIP: To enable both Bash and Zsh to use the same keyboard alias shortcuts, define keyboard aliases in a separate file and source its path in
.zshrc
. -
.zlogin is sourced in login shells. It should contain commands executed only in login shells. It should contain commands to set the terminal type and run a series of external commands (fortune, msgs, etc).
.zlogin
is not the place for kyeboard alias definitions, options, environment variable settings, etc.. As a general rule, commands in this file should not change the shell environment. -
.zlogout is sourced when login shells exit. Sometimes used to clear and reset the terminal.
See https://github.com/search?q=zsh+dotfiles&ref=commandbar https://github.com/novas0x2a/config-files/blob/master/.zshenv
- .zshenv is always sourced (run) during login and on all invocations of the Terminal shell, unless the -f option is set. If you want to de-clutter your $HOME directory by specifying an alternative location for other zsh configuration files in a subfolder, define in
-
Open
.bashrc
where zsh-completions installed. -
Create file ~/.zshenv if you don’t have one.
-
From ~/.bash_profile copy to ~/.zshenv $PATH statements
-
Copy alias, functions, key bindings, and more from ~/.bash_profile to ~/.zshrc.
Prompt settings are different
-
If you type in the command while in the Bash shell:
zsh
The response prompt can be a mess because zsh doesn’t understand prompt specifiers for Bash. For example, my
~/.bash_profile
file defines a PS1 system environment variable with this specification:\n \w\[\033[33m\] $(parse_git_branch)\[\033[00m\]\n$
\n
add a blank line and indents. For easier readability.\n
positions the cursor always on the same spot at the left of the screen so I don’t have to search for it.PROTIP: Zsh spits out the PS1 variable when it can’t find the
~/.zshrc
that it uses (instead of~/.bash_profile
to define prompts, paths, etc.Emulate Other Shells
-
zsh has a built-in command to emulate different shells:
emulate bash
- Perform commands.
-
Restore:
emulate -R zsh
-R
restores all the options to their default values for that shell.Execute zsh temporarily
-
To Switch to zsh (replace your current shell with a new shell):
exec zsh
- Command
bye
now exits zsh just asexit
in bash.
Similarly, to switch to Bash from inside Zsh:
exec bash -l
-l
or--login
avoids a source reset.zsh always reads
.zshrc
when starting an interactive shell, whether it’s a login one or not. - Command
Default to Zsh
-
To flip back to Bash shell:
sh
PROTIP: Control the look of the prompt in Bash by setting the PROMPT_COMMAND variable to one or more of the special characters will customize it for you.
-
To Switch to bash (replace your current shell with a new shell):
exec zsh
Similarly, to switch to Bash from inside Zsh:
exec bash -l `-l` or `--login` avoids a source reset.
-
Identify where shells are installed:
which zsh
Response: You would see this if zsh was installed in a way that requires sudo to change:
/bin/zsh
/usr/local/bin/zsh
Alternately,
which bash
Response expected:
/bin/bash
-
In Terminal, select Preferences > General > Shells open to change to:
/usr/local/bin/zsh
-
Close and start your Terminals for changes to take.
chsh to make zsh the default
PROTIP: Some tutorials recommend using a command such as “chsh -s /bin/zsh”. But my recommendation is instead of a hard-coded path, have the command look up where zsh is located. This is because there can be multiple versions of zsh around.
-
Use the
chsh
command:chsh -s $(which zsh)
You would be prompted “Password for …”, so give it up.
Alternately, there is an approach which directly updates the Mac’s user db, without need to edit /etc/shells, is the
dscl
(Directory Services Command Utility) also used to create new users, reset password, etc. from the command line rather than the GUI. (see the dscl man page). -
Verify the system variable that defines the shell your system defined:
echo $SHELL
If you have Z shell, it would be:
/usr/bin/zsh
PROTIP: The concern is making Z shell the default, not whether to install it.
Verify the switch
-
Verify the process running:
echo $0
If you have Bash, it would return:
bash
Alternately, if you have Z shell, it would return:
zsh
Why Z shell is better than Bash
Here is a small list of advantages to using zsh.
-
Automatic cd: Just type the name of the directory anywhere in the path (you don’t need to specify the entire path)
-
Recursive path expansion: For example “/u/lo/b” expands to “/usr/local/bin”
-
Spelling correction and approximate completion: If you make a minor mistake typing a directory name, ZSH fixes it for you
-
Z shell is case insensitive.
-
Floating point support (Bash does not have)
-
Hash data structures support (requires upgrade to Bash 4)
-
File globbing in Z uses character patterns that are similar, but not identical to those used in regexps. Example: “He said his name was [KC]arl” to (express ambiguity). See https://www.linuxnix.com/10-file-globbing-examples-linux-unix
-
To display all available options for a command, along with a short description, type the command followed by -, then hit tab. Tab through to select the option shown.
Zsh comes with commands that need to be installed in Bash:*:
-
Z shell comes with Git client and Git completions (see http://eseth.org/2010/git-in-zsh.html#show-stashed-changes)
-
Startup/shutdown scripts
zshenv
,zprofile
,zshrc
,zlogin
, andzlogout
-
zcalc
is a command-line calculator for doing quick calculations without leaving the terminal. (Load it with autoload -Uz zcalc and run with zcalc) -
zparseopts
parses complex options (arguments) provided to shell scripts -
zmv
does massive file/directory renames. To append ‘.txt’ to every file name run:
zmv –C '(*)(#q.)' '$1.txt'
- Z comes with an auto-update tool that makes it easier to keep installed plug-ins and themes updated.
See a list of Z Shell built-in commands in the Zsh Manual at:
http://zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html
More opinions about zsh:
- https://www.freecodecamp.org/news/how-to-configure-your-macos-terminal-with-zsh-like-a-pro-c0ab3f3c1156 from 15 November 2018
- http://zpalexander.com/switching-to-zsh
- https://www.chenhuijing.com/blog/bash-to-zsh/#%F0%9F%91%BE
Script Bashisms break in Zsh
PROTIP: Unlike Microsoft Windows which selects the program to execute a file based on the file name extension, Linux looks into the first line within the file. That line which is called a “Shebang”. Thus, shell scripts do not require a file extension, but many add one anyway, such as thisfile.sh
.
-
In a script, if you use Bashisms, have this she-bang:
#!/usr/bin/env bash
By contrast, the recommended way to call python is:
#!/usr/bin/env python
PROTIP: The use of
env
takes a bit longer because it goes out and finds the program rather than specifying the program “bash” in a certain path:#!/usr/bin/bash
The problem with the above location is that it is not available in other platforms and thus makes the script non-portable.
Alternately, to ensure your script runs on the widest variety of systems:
#!/bin/sh
This is because the
sh
interpreter is POSIX compliant. Bash is not.BTW In Ubuntu, the default shell was changed from bash (the GNU Bourne-Again Shell), then to /bin/sh, then to dash (the Debian Almquist Shell) in Ubuntu 6.10. That’s back when actual Bourne shell and Korn shell weren’t open-source at that time. * Dash is faster to start than bash.
There is also a Debian Posh shell, Busybox shell, etc.
There are also other distributions, such as Cygwin (emulator in Windows), MinGW(used in git bash), CentOS, Amazon Linux, Red Hat, Debian, etc.
Each flavor of shell has a different algorithm for deciding which startup script to run.
The big issue of concern is compatibility with other Linux distributions. A further shift to MacOS’s FreeBSD roots would add “cognitive overload”. because the vast majority of other CLI ecosystems remain on Bash. Constantly thinking about whether one needs to use Z shell or Bash shell disrupts the “muscle memory” of developers, and thus reduce productivity.
Cloud shells on cloud vendors use Bash
- Azure Cloud Shell https://shell.azure.com/
- Amazon
- etc.
One can configure Windows 10 to use Z shell but many use git bash which remains in Bash.
Azure’s list of its Cloud Shell features includes zsh.
Some find Apple’s move exciting because Apple is leading the rest of the tech world into the future, like Apple did about removing 3.5 mm headphone jacks on iPhone X.
So the transition will be painful, as the dream of one shell script that runs across operating systems is now dashed.
Z Shell plug-ins
The ~/.zshrc
file (~
meaning in your $HOME directory) is one file that enables and disables plugins.
For example:
plugins=( osx iterm2 brew git python pip colored-man colorize zsh-autosuggestions yarn web-search jsontools macports node osx sudo thor docker zsh-syntax-highlighting mouse )
WARNING: Adding plugins cause your shell startup time to increase.
The sequence is important. “prompt” must come last. history-substring-search must come before it, and syntax-highlighting must come before that.*
Z shell Prompts
Zsh has several built-in advanced prompts.*
-
Start Zsh advanced prompt support with
autoload -U promptinit
, thenpromptinit
-
List available prompt names with
prompt -l
. - Select a particular one with prompt prompt-name.
-
Display all available prompts with
prompt -p
. - Except for the list and display commands above, insert the other ones in
~/.zshrc
to be automatically executed at shell start, with the prompt you chose.
Z shell themes
-
The powerlevel9k theme adds a right-aligned info box, integration with git and command history, incredible customization, and wraps it all up in a slick interface based on the powerline plugin for vim.
git clone https://github.com/bhilburn/powerlevel9k.git \ ~/.oh-my-zsh/custom/themes/powerlevel9k
-
Enable it in .zshrc:
ZSH_THEME="powerlevel9k/powerlevel9k"
-
Customize the default prompt by defining POWERLEVEL9K_LEFT_PROMPT_ELEMENTS in your .zshrc. For example, to define a minimal prompt:
POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(vcs dir rbenv) POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(root_indicator background_jobs status load)
-
Read documentation at https://github.com/bhilburn/powerlevel9k#customizing-prompt-segments
Based on https://www.howtogeek.com/362409/what-is-zsh-and-why-should-you-use-it-instead-of-bash/
Other themes for Z shell:
-
https://github.com/sobolevn/sobole-zsh-theme
-
http://sobolevn.me/sobole-zsh-theme/
Bashisms against portability
“Bashisms” are shell syntax which is only understood by the bash shell and not other shells.
To enable a shell script to run on more platforms, convert use of “bashisms” to POSIX: https://en.wikipedia.org/wiki/POSIX#POSIX.2
-
Replace
function funcname()
withfuncname()
-
TODO: To verify, run linter shellcheck.
NOTE: The Ubuntu checkbashisms Perl program to identify bashisms in a script.
checkbashisms
On Debian, it’s shipped as part of the package maintainer tools.
-
If you use the Atom text editor, install the plug-in for checkbashisms.
-
Configure a Git pre-commit hook to run https://tracker.debian.org/pkg/devscripts
Some of Bash’s scripting features are derived from the ksh and predecessor shells rather than those defined by POSIX standard defined by the IEEE at http://pubs.opengroup.org/onlinepubs/009695399/nfindex.html. The shell standard 1003.1-2004 is http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
-
Set a script to disable non-POSIX usage to ensure portability, add:
set -o posix
Discussion about Bashisms are at:
-
http://www.freeos.com/guides/lsst/
-
https://news.ycombinator.com/item?id=8777705
Random
-
Rather than using the magic variable $RANDOM, use this, which returns 20816:
random=`hexdump -n 2 -e '/2 "%u"' /dev/urandom`
- Indexes in an array within zsh begin with 1 vs. with 0 in bash and sh.
vzvol is a great example of modular shell code to ensure extensibility and cleanliness of code. It sources functions from files the same way you would import functions and libraries in C.
Plugins
Z shell supports plugins and themes.
There are mutually exclusive alternatives:
-
Prezto (at https://github.com/sorin-ionescu/prezto) is a configuration framework for Zsh.
-
Antigen is a manager for Zsh plugins (bundles). Antigen lets you switch the prompt theme with a command (for the session) such as:
antigen theme candy
-
Oh My Zsh is the most commonly known.
Oh My Zsh
PROTIP: A user community website called “Oh My Zsh” at https://ohmyz.sh (@ohmyzsh) collects third-party plug-ins and themes for the Z shell. As of 2018, their GitHub repository has over 1,300 contributors, 200+ plug-ins, and over 140 themes (of varying quality).
See https://support.apple.com/en-us/HT208050 and https://github.com/robbyrussell/oh-my-zsh/wiki/Installing-ZSH
-
Use this shell command to install:
sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
The initial response:
Cloning Oh My Zsh... Cloning into '/Users/wilsonmar/.oh-my-zsh'... remote: Enumerating objects: 1040, done. remote: Counting objects: 100% (1040/1040), done. remote: Compressing objects: 100% (957/957), done. remote: Total 1040 (delta 23), reused 852 (delta 20), pack-reused 0 Receiving objects: 100% (1040/1040), 691.56 KiB | 2.11 MiB/s, done. Resolving deltas: 100% (23/23), done. Looking for an existing zsh config... Found ~/.zshrc. Backing up to /Users/wilsonmar/.zshrc.pre-oh-my-zsh Using the Oh My Zsh template file and adding it to ~/.zshrc.
-
When prompted with this, type “n”:
Time to change your default shell to zsh: Do you want to change your default shell to zsh? [Y/n] n
The rest of the response:
Shell change skipped. __ __ ____ / /_ ____ ___ __ __ ____ _____/ /_ / __ \/ __ \ / __ `__ \/ / / / /_ / / ___/ __ \ / /_/ / / / / / / / / / / /_/ / / /_(__ ) / / / \____/_/ /_/ /_/ /_/ /_/\__, / /___/____/_/ /_/ /____/ ....is now installed! Please look over the ~/.zshrc file to select plugins, themes, and options. p.s. Follow us on https://twitter.com/ohmyzsh p.p.s. Get stickers, shirts, and coffee mugs at https://shop.planetargon.com/collections/oh-my-zsh
Set .zshrc start-up commands
Installing oh my zsh results in creation or update of file ~/.zshrc
, with suggested settings commented out. Other examples are
PROTIP: Static values need to be defined to specify PATH, LANG, LC_ALL, PS1, PS2, PS4, etc. shell variables.
When the operating system starts, it looks for a file with a specific name to execute. Debian-family distros execute .profile
, and ignores the .bash_profile
that MacOS and RedHat derivatives (CentOS) execute.
The sh shell and Debian-family distros look for a file named .profile
to execute for user login. The bash shell, being generally backwards-compatible with /bin/sh, reads .profile
if one exists.
NOTE: There is a differentiation between interactive login. Each terminal window is a different process and require another password to login.
-
PROTIP: Some installers, such as the rvm (Ruby) installer, adds to the .profile file. So edit the .profile file add at the top of the a command to notify that it is being executed. Such as:
printf ">>> ~/.profile being processed ..."
-
Open the Terminal program.
This causes an interactive shell to be invoked.
You are required to provide your password because it logs you in as a user.
The zsh shell always reads file
.zshrc
for an interactive shell, whether it’s a login one or not. -
Switch to a text editor to edit in your Home folder file
~/.zshrc
:This is from here on GitHub. Robby Russell is the original developer of the project.
\# If you come from bash you might have to change your $PATH. export PATH=$HOME/bin:/usr/local/bin:$PATH \# Path to your oh-my-zsh installation. export ZSH="$HOME/.oh-my-zsh" # Set name of the theme to load --- if set to "random", it will # load a random theme each time oh-my-zsh is loaded, in which case, # to know which specific one was loaded, run: echo $RANDOM_THEME # See https://github.com/robbyrussell/oh-my-zsh/wiki/Themes ZSH_THEME="robbyrussell" # Set list of themes to pick from when loading at random # Setting this variable when ZSH_THEME=random will cause zsh to load # a theme from this variable instead of looking in ~/.oh-my-zsh/themes/ # If set to an empty array, this variable will have no effect. # ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" ) # Uncomment the following line to use case-sensitive completion. # CASE_SENSITIVE="true" # Uncomment the following line to use hyphen-insensitive completion. # Case-sensitive completion must be off. _ and - will be interchangeable. # HYPHEN_INSENSITIVE="true" # Uncomment the following line to disable bi-weekly auto-update checks. # DISABLE_AUTO_UPDATE="true" # Uncomment the following line to automatically update without prompting. # DISABLE_UPDATE_PROMPT="true" # Uncomment the following line to change how often to auto-update (in days). # export UPDATE_ZSH_DAYS=13 # Uncomment the following line if pasting URLs and other text is messed up. # DISABLE_MAGIC_FUNCTIONS=true # Uncomment the following line to disable colors in ls. # DISABLE_LS_COLORS="true" # Uncomment the following line to disable auto-setting terminal title. # DISABLE_AUTO_TITLE="true" # Uncomment the following line to enable command auto-correction. # ENABLE_CORRECTION="true" # Uncomment the following line to display red dots whilst waiting for completion. # COMPLETION_WAITING_DOTS="true" # Uncomment the following line if you want to disable marking untracked files # under VCS as dirty. This makes repository status check for large repositories # much, much faster. # DISABLE_UNTRACKED_FILES_DIRTY="true" # Uncomment the following line if you want to change the command execution time # stamp shown in the history command output. # You can set one of the optional three formats: # "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" # or set a custom format using the strftime function format specifications, # see 'man strftime' for details. # HIST_STAMPS="mm/dd/yyyy" # Would you like to use another custom folder than $ZSH/custom? # ZSH_CUSTOM=/path/to/new-custom-folder # Which plugins would you like to load? # Standard plugins can be found in ~/.oh-my-zsh/plugins/* # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ # Example format: plugins=(rails git textmate ruby lighthouse) # Add wisely, as too many plugins slow down shell startup. plugins=(git) source $ZSH/oh-my-zsh.sh # User configuration # export MANPATH="/usr/local/man:$MANPATH" # You may need to manually set your language environment # export LANG=en_US.UTF-8 # Preferred editor for local and remote sessions # if [[ -n $SSH_CONNECTION ]]; then # export EDITOR='vim' # else # export EDITOR='mvim' # fi # Compilation flags export ARCHFLAGS="-arch x86_64" # Set personal aliases, overriding those provided by oh-my-zsh libs, # plugins, and themes. Aliases can be placed here, though oh-my-zsh # users are encouraged to define aliases within the ZSH_CUSTOM folder. # For a full list of active aliases, run `alias`. # # Example aliases alias zshconfig="mate ~/.zshrc" alias ohmyzsh="mate ~/.oh-my-zsh"
mate
invokes the TextMate editor. -
Remove the
#
to activate lines.# Per Homebrew zsh Caveat: fpath=(/usr/local/share/zsh-completions $fpath) # This can also be in a ~/.zprofile : export PS1="\n %10F%m%f:%11F%1~%f \$ \n"
Source aliases for compatibility
-
PROTIP: So that you can switch between zsh, bash, sh, put settings that are common among them into a separate file and have each script invoke the file.
source aliases.sh
-
Save the files in GitHub for version control.
-
Files in the $HOME folder are backed up.
Change default shell back to bash
-
Switch back the default to Bash:
chsh -s $(which bash)
You should see the status response above.
/usr/local/bin/zsh
Why not Fish?
Why didn’t Apple go further with alternative FOSS shell Fish (Friendly Interactive SHell)? Information about it:
- http://fishshell.com is its home page.
- Wikipedia on “Friendly_interactive_shell”
- Fish Shell Overview
Why not jump temporarily to Python?
There is a rising call for coding Python rather than shell code. Python code is easier to read and maintain, runs a little faster, and can have a proper unit test suite. This article argues the Python is more cross-platform.
Examples of common OS-level actions:
- parsing arguments provided when called
- functions
- Getting the Time
- parameters
- Reading configuration files
- Downloading Web Pages and Files
-
Replace in line - https://stackoverflow.com/questions/10507230/insert-line-at-middle-of-file-with-python
sed "s/fields/fields\nNew Inserted Line/" file.txt
- Killing (and creating) processes
- subshells
$()
- Creating (and deleting) directories
- Running applications
- Doing date arithmetic
- Arrays
- symlinking files
- Managing files
https://github.com/ninjaaron/replacing-bash-scripting-with-python
Video Tutorials
-
https://commandlinepoweruser.com by Wes Bos (@wesbos) present a free yet thorough video course on Zsh.
-
Accessing and Using the Azure Cloud Shell hands-on lab on Linux Academy
-
The System Administrator’s Guide to Bash Scripting [7:28:37] video course
Other Resources
When Jessica Deen (@JLDeen), Microsoft Azure DevOps Evangelist uber-nerd shares her screen at conferences and webinars, people marvel at her terminal configuration. So she shows us how we can set it up at Badass Terminal: WSL, macOS, and Ubuntu dotfiles update!!! on March 2018 added PowerShell for Windows and support for MacOS. It updates here Badass Terminal: FCU WSL Edition (oh-my-zsh, powerlevel9k, tmux, and more!) that went viral Oct 2017.
-
https://friedcpu.wordpress.com/2007/07/24/zsh-the-last-shell-youll-ever-need
-
http://www.bash2zsh.com from Peter Stephenson in 2005 - http://www.bash2zsh.com/zsh_refcard/refcard.pdf
-
My Terminal Setup: iTerm2 + Zsh by Ali Spittel (alispit.tel), who likes the Spaceship prompt.
-
https://dev.to/sobolevn/instant-100-command-line-productivity-boost
Dotfiles for Zsh
https://github.com/MikeMcQuaid/dotfiles has 3 files:
- zlogout.sh
- zprofile.sh
- zshrc.sh
More on OSX
This is one of a series on Mac OSX:
- MacOS Setup step-by-step, with automation
- MacOS Hardware and accessories
- MacOS dotfiles for System Preferences setup automation
- MacOS Boot-up
- MacOS Keyboard tricks
- MacOS Terminal Tips and Tricks
- Text editors and IDEs on MacOS
- MacOS Xcode.app and CommandTools (gcc)
- MacOS Command-line utilities
- Applications on MacOS
- 1password on MacOS
- Manage Disk Space on MacOS
- Screen capture on MacOS
- MacOS iPhone integration
- Linux and Windows on Apple MacOS
- Packer create Vagrant Windows image
- Python on MacOS
- Maven on MacOS
- Ruby on MacOS
- Node on MacOS installation
- Java on MacOS
- Scala ecosystem