Wilson Mar bio photo

Wilson Mar

Hello!

Calendar YouTube Github

LinkedIn

Apple’s heavy hand is forcing adoption of POSIX and even switch to Python, to get away from Bashisms

US (English)   Norsk (Norwegian)   Español (Spanish)   Français (French)   Deutsch (German)   Italiano   Português   Estonian   اَلْعَرَبِيَّةُ (Egypt Arabic)   Napali   中文 (简体) Chinese (Simplified)   日本語 Japanese   한국어 Korean

Overview

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.


Among shells

First, open a Terminal on your macOS machine (on Mojave or whatever version).

In fact, several shell programs are installed with macOS:

  1. 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
    
  2. 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?

  3. 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

  4. 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).

  5. 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/files

    Install 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.

  6. 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:”

  7. 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)
    
  8. 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

  9. 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:

  10. Highlight and copy this line below

    "terminal.integrated.shell.osx": "/bin/zsh"
  11. Press command + , (comma) to open VSCode settings.
  12. Type “Bash” in the search box.
  13. In the expanded “Features” and “Terminal” menu item,
  14. Click “Edit in settings.json” Within “Terminal > Integrated > Profiles: osX” to open another tab.
  15. Press command+, (comma) to go to the bottom of the file.
  16. Type a comma at the end of the last entry and press Enter to create a new blank line.
  17. Click command+V to paste above the “}” last line of the file.

  18. Close the Settings and settings.json tabs.
  19. 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).

    1. .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.

    1. .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.

    2. .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.

    3. .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.

    4. .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

  20. Open .bashrc where zsh-completions installed.

  21. Create file ~/.zshenv if you don’t have one.

  22. From ~/.bash_profile copy to ~/.zshenv $PATH statements

  23. Copy alias, functions, key bindings, and more from ~/.bash_profile to ~/.zshrc.

    Prompt settings are different

  24. 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

  25. zsh has a built-in command to emulate different shells:

    emulate bash
  26. Perform commands.
  27. Restore:

    emulate -R zsh

    -R restores all the options to their default values for that shell.

    Execute zsh temporarily

  28. To Switch to zsh (replace your current shell with a new shell):

    exec zsh
    • Command bye now exits zsh just as exit 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.

Default to Zsh

  1. 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.

  2. 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.
    
    
  3. 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
  4. In Terminal, select Preferences > General > Shells open to change to:

    /usr/local/bin/zsh

  5. 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.

  6. 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).

  7. 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

  8. 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, and zlogout

  • 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:

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.

  1. 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/
  • Google
  • 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.*

  1. Start Zsh advanced prompt support with

    autoload -U promptinit, then promptinit

  2. List available prompt names with prompt -l.

  3. Select a particular one with prompt prompt-name.
  4. Display all available prompts with prompt -p.

  5. 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

  1. 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
  2. Enable it in .zshrc:

    ZSH_THEME="powerlevel9k/powerlevel9k"
  3. 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)
    
  4. 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

  1. Replace function funcname() with funcname()

  2. 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.

  3. If you use the Atom text editor, install the plug-in for checkbashisms.

  4. 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

  5. Set a script to disable non-POSIX usage to ensure portability, add:

    set -o posix

Discussion about Bashisms are at:

Random

  1. 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

  1. 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.
    
  2. 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.

  1. 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 ..."
  2. 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.

  3. 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.

  4. 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

  5. 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
  6. Save the files in GitHub for version control.

  7. Files in the $HOME folder are backed up.

Change default shell back to bash

  1. 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:

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

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.

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: