As a Linux user, you probably run commands in your terminal using one of two shells: bash or zsh. Maybe you've heard of their predecessors, like sh or csh; you might even be aware of newer shells like fish. But what about these modern alternatives: can they make a meaningful difference to your everyday work?
fish: The Friendly Interactive Shell
The fish shell is one of the most widely known modern alternatives to whichever shell your distro uses by default. It emphasizes user-friendly features, with powerful tab completion, syntax highlighting, and command suggestions.
fish is available for Linux and macOS, so starting to use it can be as simple as running brew install fishor apt-get install fish.
If you're familiar with zsh's excellent tab completion, fish will make you feel right at home. Start typing a command, and fish will suggest a completion, in grey, after the characters you've already typed:
This suggested completion is based on your command history and valid file paths, so it's often very useful. Type more letters, and fish will refine its suggestion. You can accept the suggestion by pressing Right, and pressing Tab will give you a set of options that you can navigate using the cursor keys:
If you show suggestions for the command itself, you'll see all matching commands, with information about what each of them does:
You can also use the auto-suggest feature to view available options by pressing Tab after a single - character:
fish is highly configurable, but it often takes a different approach to more common shells like Bash and Zsh . For example, customizing your prompt is one of the first things you'll learn to do when you start using the terminal , but fish ships with quite a unique prompt by default:
This prompt abbreviates directory names in the current hierarchy to a single letter and prints the branch name if you're inside a git repository, so it's pretty useful by default. But you can also change the prompt using a fish function, by typing the following on the command line:
The functional approach is quite a step up from Bash's PS1, which is a string variable with a predefined syntax.
Similarly, although fish supports the PATH variable much like other shells, it's actually a list variable under the hood, not a string. This helps make it easier to modify, with a helper function named fish_add_path:
A friendly way of configuring fish is provided via its web interface. Simply run fish_configfrom the command line, and fish will open a browser window with a basic UI that lets you change various settings:
You'll need to be aware of fish's differences, especially for common features that you may be familiar with. For example, I make heavy use of Bash's !$ to repeat the last argument of the previous command, e.g.
fish does not support the same !$—neither does it support $0, $? ($status is used instead), nor !!. You can insert the previous command's last argument with Alt + Up, and there are equivalents for most of the rest, but you may have to adapt some very ingrained behavior to get used to these alternatives.
Because of such differences, fish is not POSIX-compliant, which means that its scripts are not compatible with POSIX-compliant shells like Bash and Zsh.
Murex: Intuitive and Content Aware
Murex is a fairly new shell (2017), written in Go. This shell has native support for complex data formats, including dictionary objects, CSV, and JSON. This means that you can do things like:
The above code defines a JSON variable that you can use just as you'd use a structured object in JavaScript:
To make use of its more structured approach, Murex offers its own alternatives to common commands. For example, the f builtin is similar to the ls command; it lists files in the current directory, filtered by one of several available flags:
The big difference here, though, is that the output is a JSON array instead of a list of strings:
Likewise, the g command performs the same kind of globbing operation you'll be used to from Bash:
You can use Murex's extended pipe syntax to work with structured data from commands. Traditional Unix shells pass data through pipes as strings, but Murex's more powerful data types need special piping of their own.
The generic pipe (=>) is much like a classic pipe (|), but it converts output into a friendlier format for external commands that don't support Murex data types. For example:
While the traditional pipe turns f's output into a single line, the generic pipe formats it as a list of its contents, with one item per line, so the wc command can correctly report the number of items.
This concept works best with Murex's data manipulation operators. These let you access and alter structured data, so that you can pipe the output from one command into another that reformats that data or operates on it further. Here's an example:
In this command, the [[ ]] syntax accesses the nested element within the output from config:
My biggest complaint with Murex is its documentation—or lack of it. For example, the default prompt is simply "murex" which isn't very useful. I went down quite a rabbit hole trying to work out how to change this; like fish, Murex does not support the standard $PS1 variable.
However, unlike fish, Murex fails to clearly explain how to change its prompt. I found conflicting (possibly out-of-date) information about the onPrompt event, which looked like a complicated (although powerful) way of setting the prompt, similar to fish's functional approach. I couldn't get it to work, but I found a config setting which appeared to do what I wanted:
This is a useful prompt that not only shows an abbreviated version of the current path, but also colors the » symbol according to the status of the last command. However, I couldn't find any documentation on this config setting; I had to uncover this snippet from a random GitHub gist .
Nushell: A New Type of Shell
Many shells are superficially similar, their differences confined to low-level scripting features or subtle changes in syntax. This is not the case with Nushell (Nu), a shell program written in Rust that was released in 2019. As soon as you run your first command under Nu, you'll see a big difference:
This is because, like Murex, Nu supports structured data. However, Nu takes this a step further, providing its own equivalents of common commands (or builtins) like ls. This approach can produce a lot of output, although the table formatting is usually easier to read than the normal Bash form:
You can also use Nushell to pipe data from one command to another, taking advantage of its structure. For example, you can very easily fetch and extract data from a web API using two of Nushell's builtins, http and get:
The get command lets you process structured data. In this case, you can use an equivalent shorthand:
Nushell's default behavior and clear, modern interface make it an excellent choice for a next-generation shell. It's well documented, easy to use, and usually does what you'd expect.
I only have a couple of issues with Nushell. The first is pretty trivial, given today's storage costs, but it's a big shell compared to the alternatives: 39MB. To put that into context, zsh is only 1.3MB.
I also saw some strange behavior with ls -d. This is a time-consuming call because it acts a bit like du, summing up the total size of directories. But I saw its output split into separate tables for some unknown reason, which felt like a small bug.
PowerShell: The Windows Shell, Now for Everyone
PowerShell is a Microsoft program that offers Windows users similar capabilities to Linux shells. Although it is heavily integrated with the Windows operating system, a version is now available for Linux and Mac users to try; in fact, it has been since 2016.
You can install PowerShell on Mac using Homebrew ( brew install --cask powershell) and on Linux using the instructions for your particular distro . Once installed, run it with the command pwsh.
PowerShell brings with it familiar MS-DOS commands like dir:
Combine it with a tool like Microsoft's Edit for Mac and Linux , and you could almost convince yourself you're running MS-DOS, should you want to.
Because PowerShell is implemented just like another shell, you'll still have access to familiar Unix commands, so you can ignore the DOS equivalents if you prefer.
The real value of PowerShell is that, like Murex and Nushell, it has a powerful data model that operates on objects rather than strings. This is most apparent when chaining commands in a pipeline:
Here, Get-ChildItem and Select-Object are Cmdlets, native commands that perform small tasks, typically within a pipeline. Cmdlets are written in .NET languages, and PowerShell includes an API that Cmdlets can use to perform low-level tasks.
PowerShell really feels like a blast from the past to those of us who remember using DOS forty years ago. But I don't really miss that experience; there are reasons I moved to Linux and macOS, after all. This shell will remain an interesting curiosity to me, but it's bound to be more useful if you use both Windows and Linux.
Alternative shells seem to be just on the brink of breaking through, without quite toppling the behemoth that is Bash. Most of us will stick with the default shell, but it's nice to have options, especially when they offer such unique and powerful features as these shells. Ultimately, however, I think they will remain niche until they fully embrace POSIX compliance.
