Exit Statuses, Return Codes, String Test Conditionals, and More Special Variables
Start course
2h 3m

In this course, you'll learn how to create new user accounts. In that script, you're going to make sure the person who executes the script has the proper privileges to do so and you're going to make sure the specified account was created successfully. After that, you're going to expand it and make it better by automatically generating random passwords, accepting command line arguments, and so on. You'll learn all the concepts and techniques to build that script and complete your first project.

This course is part of the Linux Shell Scripting learning path. To follow along with this course, you can find all the necessary resources here.

Learning Objectives

  • Get started with naming, permissions, variables, and built-ins
  • Learn about special variables created by the shell, how to store the output of a command in a variable, and learn about if statements
  • Learn about exit Statuses, return codes, and string test conditionals
  • Learn how to get input from the person executing the script and how to create an account on a Linux system

Intended Audience

  • Anyone who wants to learn Linux shell scripting 
  • Linux system administrators, developers, or programmers


To get the most out of this course, you should have a basic understanding of the Linux command line.



In a previous lesson we used the if statement in a positive form meaning if this expression is true then do something. In this lesson we're going to use the logic of if this expression is not true then do something. You're also going to learn how to determine if a given command failed or succeeded by checking the exit status of the command as well as how to control the exit status of your scripts. You can follow along with me right now if you'd like, or you can wait for the practice exercise where you'll get to apply all the concepts you've learned so far. The first thing I'm going to do is open up a command line session on my local machine and move into our working folder. From here I'm going to go into the project folder that we're working on, which is local users. Now I'm gonna start up the virtual machine and connect to it. Now that I'm inside the virtual machine I'm going to CD into the shared directory of slash vagrant. And I'm going to start working on the script for this lesson, which is lusers, which stands for local user, Of course, we start out our shell scripts the exact same way every time. We supply the interpreter to be used on the shebang line here. Now we're going to specify a goal for our script. So this script is just gonna display the UID and username of the user that's executing the script. And we're also going to display to the screen if the user is the vagrant user are not. So we're going to test for the vagrant user. I'm gonna go ahead and put the steps in as comments and then fill in the code as we go. So the first step we want to do is display the UID. The next thing we're going to do is only display a message if the UID does not match 1000, from there we're just going to display the username. Then we're going to test if the username command succeeded. From there I'm gonna demonstrate how you can use a string test conditional. Next, we're going to test for not equal for the string. So let's go back to the top of our script here and start filling in some code. So the first thing we want to do is display the UID. As you already know, the UID is a shell variable that is set by default, so we can just display that. We're going to use double quotes because we're going to have a variable in here that we want to get expended. Of course, when we access a variable we access it with a dollar sign, an opening curly brace, the variable name and a closing curly brace. So let's just write and quit our changes here and then execute the script and see what happens. Remember the script has to have the executable bit set on it before it can be executed. So we're going to chmod the script. Now we're going to execute it with ./ Okay, it displays are UID, which is 1000. Now let's get back to the script and continue editing our script here. Now, what we want to do is only display a message if the UID does not match 1000. So we're going to have a variable called UID to test for and we're going to set that to 1000. By the way there's this concept called DRY, which stands for don't repeat yourself. We're going to apply that concept in this script through the use of a variable. We're going to reference this UID more than once. So instead of hard coding that UID in multiple places in the script you're going to specify that value in one place. If you ever wanna change that UID you only have to change it in one place and not go searching all throughout the entire script and change it in multiple places. In a small script like we're writing here it might not look like that such of a big deal, but when you create longer more complex scripts you're going to be glad that you followed the DRY principle. Okay, so let's test for this UID with an if statement. We remember that we used the if keyword followed by a space, double opening brackets followed by a space. We're going to look at the UID and we're going to see if it's actually not equal to the UID that we're going to test for. If the UID is not equal to the UID to test for then we're going to display your UID does not match UID that we're testing for. Let's say we don't want the user to go any farther unless they have the UID of 1000. In order to stop the execution of a script we're gonna use the exit command. By the way, we can supply an exit status after the exit command. We're going to supply one here. The reason why we're going to specify at one is because the script does not successfully execute all the way through the bottom as it should. So we're going to want to exit with a non zero status. So by convention, when a script or a program execute successfully it returns an exit status of zero. If it doesn't execute successfully, for whatever reason it returns a non zero exit status. A lot of times that exit status is one. However, it could be two, it could be 99. It could be 244. You can use a variety of different exit statuses if you want. Let me close out this if statement and I'll show you an example. Let me write and quit real quick. So let's look at a command that we're going to use. We're gonna be using the user add command to add users. So let's take a look at it's man page. I'm going to search for exit statuses by /exit and press enter. So here it's calls them exit values. The user add command exits with the following values, zero it's a success. You can actually test for these exit statuses and we'll get to that in just a minute. So, for example, exit status of nine means the username is already in use. So if you're writing a script and you run the user add command and you get an exit status of nine then you can know that that username is unused and it's not for some other reasons such as an invalid command syntax, which would be an error status of two. So again, we're going to use the exit shell built in. And let's get some help about that. Let's see what help is available for exit. So as you can see, you can use exit without any options because the N there is in brackets, that means it's optional. So you can just type exit and it exits the shell. If you want to supply an exit status you just supply it to exit. Exit one, for example, like we're using an our script. If you will admit that status then the exit status is that of the last command executed. Sometimes that's what you want and sometimes that's not what you want. So if you wanna be explicit then specify a exit status following the exit shell built in. Let's get back to our script real quick here. So now we've gone over the exit status. So let's review where this dash ne came from. So if the UID is dash ne, which means not equal to the UID to test for, then we're going to execute this code. Hopefully you can remember that you can get information about these tests by running help test. And here we're doing arithmetic tests, means we're testing numbers. Here we have dash eq, which corresponds to equal, dash ne is not equal, dash lt is less than, dash le is less than or equal, dash gt is greater than and dash ge is greater than or equal to. So we're using dash ne to test for not equal. Now let's go ahead and execute our script and see what happens. It says your UID is 1000 and no messages were displayed to the screen because UID does not equal 1000 is actually false. Now let's see what happens when we execute the script of the different user ID. Well, one way to do that is to execute it with sudo privileges. And that will run the script with root user privileges. And as we know, the root user always has the UID of zero. So this time you get your UID is zero. Your UID does not match 1000. So the if statement evaluates to if zero not equal 1000 then do something which is two echo, your UID does not match 1000. Okay, let's continue working on our script. Now let's display the username. As you probably remember the dollar sign parentheses syntax is used to capture the output of a command. And we're going to send the output of that command and store it into the variable user underscore name. Now what we want to do is test if that ID command succeeded and how we do this, of course, is with an if statement. So has some special variables that it sets. And one of these special variables is a dollar sign question mark. And of course, as you know you can encapsulate that in curly braces. So dollar sign opening curly brace, question mark closing curly brace is actually a special variable that holds the exit status of the most recently executed command. So the most recently executed commanded our script is id-un. So the exit status of that script is going to be stored in dollar question mark. Now we can use dollar question mark to do some comparisons here and make a decision. So if dollar question mark does not equal zero then what we want to do is tell the person that's executing this script that the ID command did not execute successfully. And we're going to cause our script to exit as well. So we'll just do exit one and then close our if statement. If we get past this, if statement that means the ID command did successfully complete so we can display their username. So let's execute this script on the command line and also do some demonstrations with the dollar question mark special variable. So now the output of the script is your UID is 1000. Your username is vagrant. And as you remember the username is a vagrant echo command was directly after the if statement so the if statement did not execute. So that means the ID command actually executed properly. So let's test this out. Let's do id dash un, which we know is a good command to get the username of the current user. Again, the special variable dollar question mark contains the exit code. Let's look at it. So we'll do echo dollar question mark. And the exit status of the ID command is a zero. Now let's make the ID command fail in some way. I happen to know that dash x is not a valid option to ID. So let's run that command and see what happens. So we get an invalid option dash x. So now let's look at the exit status, which is stored in dollar question mark. So now you can see that one is the exit status of that command that failed. So again, by convention it's a non zero exit status. In this case it's one. Again, it could be two, it could be three, it could be 100. It could be nine in our user add example that we were looking at earlier. So again, if we want to test for success we'll probably want to test if it does not equal zero because that's the convention. Okay, let's continue with our script. Instead of testing numbers let's do a test against a string. So let's have a username to test for. We'll use an if statement to perform a test. So this reads if the username equals the username to test for, if that turns out to be true, then what we want to do is echo your username matches the username that we're testing for. It's important to point out that the equal sign can either be an assignment operator or a test operator depending on the context. If you look at the variable assignment username to test for that equal sign is used as assignment, we're assigning the value of vagrant into the value of username to test for. However, when we're doing a test inside these double brackets, then it's a test operator. It's not assigning username to test for to username. It's comparing them, it's testing them. By the way, sometimes you'll see a double equal sign. And let me put this in the script to show you here. So sometimes you will see that. When you use the double equal sign operator the string to the right of the operator is used as a pattern and pattern matching is performed. So we're not looking for a pattern. We're looking for an exact match. So we'll just use one equal sign. However, some people even use the double equal signs when they don't use a different pattern if they're also using the exact match. So be aware that sometimes you'll see a single equal sign and sometimes you'll see a double equal sign. We're going to stick with a single equal sign in this case. Okay, let's exit out of our script and see what happens when we execute it now. It says our UID is 1000, our username is vagrant, and our username matches vagrant. Well, let's run this with sudo. Your UID is zero. Your UID does not match 1000. And again, if you remember, we had an exit statement in our script and we exited as one. So let's check the exit status and see if that's true. And sure enough, the exit status of our script is one. Okay, let's get back to our script and finish it up. Now let's test for inequality using an if statement with a string. So we'll do if, double brackets, the username is not equal to username to test for then we're going to echo your username does not match user name to test for. And then we're going to exit with one. And we're going to end the statement with fi. And finally if we may get all the way to the end of the script we can use exit and we can be very explicit about the exit status that we want to use. We'll use zero to say our script completed successfully. Remember that if you don't specify an exit status or exit code, the exit status of the most recently previously executed command will be used as the exit status of your script or as the exit status of the exit command. Okay, that wraps it up for this script. Let's save our changes and execute it at the command line. So you can see the output on the screen and let's check our exit status. Okay, we have an exit status of zero, which means by convention that our script completed successfully.

About the Author
Learning Paths

Jason is the founder of the Linux Training Academy as well as the author of "Linux for Beginners" and "Command Line Kung Fu." He has over 20 years of professional Linux experience, having worked for industry leaders such as Hewlett-Packard, Xerox, UPS, FireEye, and Nothing gives him more satisfaction than knowing he has helped thousands of IT professionals level up their careers through his many books and courses.

Covered Topics