https://timvisee.com/blog/elegant-bash-conditionals/ Tim Visee * Home * Projects * Blog * About * Donate * Contact Elegant bash conditionals # 4 minute read Published: 2021-03-02 Table of contents [Elegant bash conditionals] The if-statement is a very basic thing, not just in bash, but in all of programming. I see them used quite a lot in shell scripts, even though in many cases they can be replaced with something much more elegant. In this rather short article, I'll show how control operators can be used instead. Many probably know about this, but don't realize how to use them nicely. This will help you write cleaner shell scripts in the future. Here is what a simple if-statements looks like in bash: if [ expression ] then command fi # or if [ expression ]; then command; fi Ughh. Let's improve! Control operators # Bash provides control operators to build sequences of commands. Some of these are conditional and allow logical branching based on the success state of the last run command. We will just focus on these two logical operators: * &&: the AND operator, run the following command only if previous succeeded * ||: the OR operator, run the following command only if previous failed Exit codes # You might wonder how bash considers whether a command succeeded. This is where exit codes come in. When a program exists a numeric status code is returned. A value of 0 means the program succeeded, any other value means it failed. The exit code is normally hidden. The status of the last run command is stored in the ? variable. You may inspect it by invoking: echo $? E.g., listing with ls normally returns 0, but this value differs if the directory doesn't exist or if an error occurred. ls ~/ # exit code: 0 ls ~/nonexistent # exit code: 2 This will function similarly to almost any program. Chaining commands # Let's go over some examples to show how these control operators can be used. Imagine you want to source the ~/.profile file, but only if it is readable: if [ -r ~/.profile ]; then source ~/.profile fi We can simplify this using control operators: [ -r ~/.profile ] && . ~/.profile Only if the readability check expression is truthful/succeeds, we want to source the file, so we use the && operator. To require invoking user to be root, we can do the following: [ $USER != "root" ] && echo You must be root && exit 1 The echo command always exists with 0, so this propagates to exit if the first expression is truthful. If we'd like to print our profile file contents with a success message, or an error message on reading failure, we can do the following: cat ~/.profile && echo This is your profile || echo Failed to read profile You can make these command sequences as long as you want. Useful for building install scripts that go through a series of steps. You could define bash functions for each step and orchestrate the installation like this: init && configure && install && cleanup || echo Install failed Or format it differently to make long sequences better readable: init && configure && install && cleanup || echo Install failed Nice to know # There are many more control operators, including list terminators, pipe operators, and others. The [ (commonly used in if-statements) isn't just a shell feature. It is a binary on Unix-like systems, usually located at /usr/bin/[, so it can be used anywhere. It returns the exit code 0 if the expression was truthful. You can chain multiple [ expr ] && [ expr ] expressions together, they are commands after all. The true and false commands do nothing more than returning 0 or 1. Bash features parameter expression. You can use ${EDITOR:=nvim} to set the EDITOR variable to nvim only if it is empty, so you won't even need conditionals. Most other shells support similar operators. fish uses ; and and ; or, but now supports && and || as well in modern versions. $_ (or Alt+.) is your last used argument (thanks @Diti). For example: test -f FILE && source $_ || echo "FILE does not exist" >&2 Closing thoughts # These command sequences with control operators are an elegant alternative for simple if-statements. I think they look much better and are more expressive looking at conditional logic. But, don't overuse them. For bigger statements or advanced branching, you should fall back to if-statements. I hope this article motivates you to make your shell scripts a little more elegant in the future by using these operators. Comments Comments on Hacker News, Reddit, Lobsters & Mastodon. Published by Tim Visee in Blog and tagged bashshell Copyright (c) Tim Visee 2011-2021. * Tags * Categories * Source