For as long as bash scripts have been around, developers have been using them to help other people install their software, handle any necessary automations on their systems, run reports on their software, and much more. Because bash scripts run natively on many systems without having to install any special tooling, they are a popular way to make any scripts that you write as easy-to-use as possible.
However, once you start writing anything more than a very straightforward script, you will likely discover that you need to start taking some sort of input from the user to allow the script to execute in different ways. This is where passing arguments to your script comes in.
In this article, we'll take a look at a couple different ways to use arguments in your bash script, some of the considerations that can help you decide how you want to handle those arguments and how to make your scripts even more resilient using some generally-available tooling.
Why use bash scripts?
Bash scripts allow you to string many different commands together to create an automated process. They’re often used for:
- Automated processing of files: Often, files need to be converted from one format to another, combined from multiple different sources, or parsed for specific pieces of information. Bash scripts make dealing with files, especially text-based files, straightforward.
- Querying information about the system they are running on: Bash scripts are very useful for displaying information about various pieces of your system. They are frequently used for querying for current memory usage, which files and ports are available on a given system, and more.
- Create a common language for most anything that needs to run: Regardless of which programming language you use, creating and running scripts in that language can be run through the shell with a bash script.
Using bash script arguments: three methods
When you want to use bash script arguments, there are generally three ways to do so: positionally, looping, or by using flags.
Positional arguments are a set of up to 9 pieces of data that a bash script has access to after it's called. When using positional arguments, each value that you want to pass into the script needs to be written into the command line after the name of the script itself. For example, if we have a script called
hello_world.sh and we want it to respond with a specific person's name, we might call our script like this:
Because we have a space between the name of our script and the word "John", bash knows to interpret John as the first positional argument. And because "John" is now an argument, it can be access as a variable within your script.
Bash makes the variables
$9 available for positional arguments.
$0 is always equal to the name of the script that's being run, which is useful if you need to reference anything about the script you're running inside the script itself. But since "John" is the first positional argument, it's accessible under the variable
$1, which means to make our
hello_world.sh script greet a specific person, we could write something like this:
Then, when we run our script, we get the following output:
Looping through all provided arguments
When you might have more than the 9 arguments that the positional argument structure supports or when you want your script to be a bit more flexible with accepting arguments, looping can come in handy. To enable us to loop through all the provided arguments, we can reference the
$@ variable. Let's take a look at how you could update your "Hello World" script to be able to greet multiple people.
To enable this behavior, let's first assume that your script to be invoked with multiple names passed as arguments, like this:
While you could access each of these arguments using the positional variables discussed earlier (John being
$1, Julie being
$2, etc), if you're unsure how many names you're going to be given, hardcoding each of these variables won't always work. If instead you update your script to use the
$@ variable, you'll be able to access as many names as are passed in. For example:
Now, each person passed as an argument to your script will be greeted individually.
Positional arguments are easy to understand and easy to use in your scripts, however, they require the user to remember the order in which they need to be passed and are limited to 9 each time you call your script. If you start to run into these limitations, using flags is another alternative.
A flag is a single letter preceded by a dash that usually represents something about the data that it's flagging. For example, if you wanted to create a flag for our name argument, you might use
-n. To configure this, you might add something like this to our script:
getops is used for parsing the arguments passed to a script. In this case, you tell it to expect an
n flag. Then inside our
do block, we define the behavior you want the script to have when the n flag is present (in this case, setting whatever comes after the
n flag into a variable). You can also use the
* to define the default behavior if
getopts is asked to parse an option you haven't defined behavior for.
Calling this updated script using the newly-created flag gives us the following output:
Now that arguments can be provided via flags, there is a bit more structure to how users are expected to interact with your script. However, exposing all the possible flags to users and adding more helpful error-handling when flags are misused is an important step as well.
While you're free to write formal documentation and share it with anyone who is going to use your script, a popular convention is to bundle the documentation with the script itself, either through the use of a flag, or to be displayed when the available flags are used incorrectly.
One option for providing this documentation is to add a flag (such as
-h for help) that users can use when invoking your script to get more information about how the various flags can be used. For example adding a
help function that prints out some information to the screen like this:
This tells the user that the
-n flag can be used to input someone's name and that the -h flag is also available. Then, to actually print this to the screen when a user asks for help, you would add a
-h flag in the same way our
-n flag is currently set up, except that it would call the
help() function when it was added to the command:
Displaying the help text when options are called incorrectly
Now that we have a
help() function defined, we can also provide it to users who don't explicitly ask for it, but who use the script incorrectly. There is already a fallback case for when an invalid option is passed to our script, and by adding a call to the
help() function as part of that we can display more information to the user about how flags are intended to be used in our script. After making that update, the finished script looks something like this:
Airplane: a better way to run shell scripts
Bash script arguments are incredibly useful to make your scripts even more flexible and allow for a range of user input. By allowing users of your script to input different pieces of information and change the output of the script accordingly, your scripts become useful in many more use cases.
A way to make these scripts even more powerful exists using Airplane. Airplane is a developer platform that allows users to transform scripts, queries, and more into powerful tasks and UIs within minutes using code. The basic building blocks of Airplane are Tasks, which are single or multi-step functions that anyone on your team can use. Airplane also offers Views, which allow users to build custom UIs within minutes.
To try out Airplane yourself and make your shell scripts accessible to your team, even if they're not comfortable with the command line, sign up for a free account or book a demo. If you are at a startup that is series A or earlier with under 100 employees, check out our Airplane Startup Program for $10,000 in Airplane credits for a year.