1. Home
  2. Training Library
  3. Cloud Computing Fundamentals
  4. Courses
  5. Password Generation and Shell Script Arguments

Exercise: Creating Local Users

Start course
1h 37m

In this course, you'll learn how to generate some random data, including how to automate the process of generating a random password. We'll then look at a range of shell script statements and parameters including positional parameters, arguments, for loops, special parameters, while loops, infinite loops, shifting, and sleeping. Finally, we'll walk you through how to add users to a Linux system.

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

Learning Objectives

  • Automate the process of generating a random password
  • Learn about a variety of statements and parameters that can be used in shell scripting
  • Learn how to add a user to 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.


Welcome to the exercise walkthrough. Now, the goal of this particular exercise is to create a shell script that adds users to the same Linux system as that shell script was executed on. This exercise actually builds upon the previous exercise. It's gonna be very similar. We're just going to really make a few improvements. And by the way, that first script you created in our scenario has been used by the help desk team to create accounts. And they're really happy about it, but after using it for a little while, they have some requests. They would like you to make some changes to it when you get a chance. And of course, you're so nice that you're going to oblige. One of the requests they have is that they're kind of tired of coming up with passwords every time they create account. And they think you could automate that for them, just generate a password for the account so that they don't have to do that. Another thing that they found when using that particular script was that they already knew all the information that they were going to provide the script. However, they would have to wait to be prompted in order to type in that information. And they thought it would be just a little bit more efficient if they could just type everything right in at the command line all at once and not wait to be prompted. So again, you go back to thinking about the requirements, what the script should do, and a lot of these requirements are going to be exactly the same as you had in the first exercise. The first thing that's a little bit different is that you're going to name the script something else just to distinguish it from the previous script so that they know they're running the new script and not the old script. So, you decide to call this script add-new-local-user.sh. Like your previous script, it's going to enforce that it be executed with superuser or root privileges. And if the script is not executed with superuser privileges, it will not attempt to create a user and simply return an exit status of one. Here's something you decide to add to the script that wasn't requested by the help desk team but you can see how this would be helpful. And that thing is to provide a usage statement much like you would find in a main page if the user executing the script does not supply an account name on the command line. And if they do that, you teach them how to use the script. This script again is a little different than the last one. So, maybe they're used to getting prompted but this script requires them to have a username. So, you're going to tell them about that. And when you tell them about that, you're also going to exit your script with a status of one. Now, speaking of supplying things on the command line, you decide that the first argument provided on the command line should be the username for the account and any additional remaining arguments on the command line will be treated as the comment for the account. And that's pretty smart because the account is always going to be one word or one item, and the description could be nothing or it could be a name like Jane Smith or it could be a description of an application for which the account is being created. The next requirement you've listed is to generate password for that new account. And again, you're not going to prompt for this password. You're just going to create it inside the script. Just like in your previous script, you're going to inform the user if the account you're trying to create was not able to be created for some reason. And in that particular case, you're going to exit the script with an exit status of one. Finally, you're going to display the username, the password and the host where the account was created. This is just like in your previous script. So at this point, let's go ahead and use the existing virtual machine we used in the first exercise. So, we'll move into that Vagrant project folder. Now we just run Vagrant up to start the virtual machine. Now connect to it with Vagrant SSH. Once you're connected, you can move into the shared folder of /vagrant. At this point, you can either create the script inside the virtual machine using your favorite editor, be it Vim, Nano or Emacs, or you can create the script on your local machine using your favorite editor there. But if you do that, just remember to place your script in the shared folder, which you'll be able to access here on the virtual machine and the /vagrant folder. I'm going to use the Vim editor and just create it here on the local machine. So, I'm going to type Vim add-new-local-user.sh. Of course, it goes without saying that every script starts with a shebang. And then we're just going to provide some information, a header, if you will, for this script. So here, we're just saying that the script creates a new user on a local machine and that the first thing on the command line after the script has to be a username and anything that comes after the username will be considered a comment for the account. Next, we're going to automatically generate a password. And finally, we're going to display that information. Perhaps, that's a bit verbose for a header but you can use this or your own language or even use the usage statement that we're going to come up with here in just a minute. So of course, we really don't want to do anything unless the user that's executing the script is doing it with proper permissions. There's no reason to try to add a user account when you don't have root permissions. So, let's check for that first. And again, this is exactly the same thing you did in your first script. So, the user ID is not equal to zero. Then that means the user is not root. And then we'll exit with an exit status of one and close out our if statement here. Now, the next thing we want to do is make sure that they supply at least one argument. It's required that they give us a username. So, we'll go ahead and check for that next. So, if the number of arguments is less than one then you can do this. You can give them a usage statement. And just echo back to them the command that they just executed. Tell them that the username is required. And you're going to put comment in brackets here because that's optional and there could be more than one comment or more than one word. And so to repeat that, you just signify that with three dots here and then close the echo command. Now, you don't have to use this exact statement. You could have come up with something on your own. You could have written this in paragraph form but if you're used to reading man pages and built in help with Bash, you'll see this very same thing, this very same format. So, there's no use in reinventing the wheel here. We'll just go ahead and use the same thing that we see everywhere else. Again, if you come up with something different, that's totally fine. Obviously, it works. This is not going to affect the execution of the program. We'll give them some more information here. And then we'll exit with one because the script didn't complete. And now that we're sure that they have provided a username, we can go ahead and assign that username to a variable. So, I'll just use USER_NAME and assigned the value of whatever is in the first positional parameter to that variable. Now as you already know, our requirements and the help statement that we just wrote here that everything else on the line are considered comments. Since we've already assigned username to the value that was stored in the first positional parameter ${1} there, we no longer need ${1}. So, what we can do is use the shift command to shift everything down one more or less making ${1} drop off or get chopped off. And then what is left, obviously, are the comments. So, that means we can do this. We can assign the variable comment to every thing else. Now, remember ${@} is every positional parameter starting at one and beyond. So, this captures everything that's left on the command line. Again, running shift, took the username out of the positional parameters. And then again, what's left is gonna be the comments. Now, what you wanna do is generate a password. We'll assign this to the password variable. Again, you could use any variable name that you would like. That's a valid variable name. This is just what I happen to come up with. Now, we're going to use command substitution, starting that with a $ and then an open parentheses. And then here is where you'll put the command that will generate a password. In previous lessons we've went over a few different methods and you just simply can pick one, your favorite one or the one you think makes most sense and use it here. So, you don't have to use this exact method to generate this password, either. I'm going to create a 48 character password. So, this is how I'll do it here. Now, we have all the information we need. We got the username from the command line. We also got the comments from the command line. We didn't ask for a password. We went ahead and generated on our own. And so, now we're ready to create the account. The -c stands for comment. And so, we'll supply the comments to the -c argument here. And we're going to put those comments in quotation marks so that they are treated as one thing, one argument to the -c option. Now, we can use -m to force the creation of a home directory. And now, the only thing we have left to supply is the username. At this point, what we wanna do is check to see if the useradd command succeeded. Of course, if it didn't succeed for some reason, we don't wanna tell the user that, "Hey, we created an account when we actually didn't." So, we'll want to exit out of our script as well. So, what we can do here is check for the return status. So, if ${?}, which contains the exit status or return status of the most recently executed command. If that does not equal zero, then something went wrong. So then what we'll say is the account could not be created and we're going to exit with a non-zero exit status as well. Now we need to set the password on the account and we'll just echo the password into the password command with a standard in option and then we'll supply the username that that password is for. So again, the output of the command that proceeds the pipe, that comes before the pipe, is used as the standard input of the command that comes after the pipe, which in this case is password. And we're telling it to read standard in with -- S-T-D-I-N. Let's check to see if the password command succeeded as well. We'll just tell the user that the password couldn't be set and then exit with one. The last thing we need to do is to force a password change on first login for the account. So, we'll do this force password change. Now, we're just going to display the information. Print out a blank line because we know those password command generate some output. So, we just separate them with a blank line and then we'll display the username. Another blank line. And we'll display the host name, which is a built-in variable in Bash. We've made it to the end here. Obviously, the script succeeded. So, we're going to exit with an exit status of zero. Now it's time to save our changes. Now, remember to set the permissions on the script before you try to execute it. So, we'll do that now with chmod 755 add-new-local-user.sh. Now, let's go ahead and test the script. Of course, we're creating accounts so we need root privileges. And one way to do that is to use the sudo commands. So, we'll use sudo and then we'll use ./ and the name of the script. By the way, I'm Tab completion here. I just typed in the first few letters of the command name there and then hit Tab. And I let Bash complete that for me. So, I don't think I'm a super fast typer. I'm just using some shortcuts and that's when you probably already know but just to be clear here, that's what I'm doing. So, now what we need to do is supply a username. So, we'll create the account name of J-L-O-C-K-E. And then what we can do here is provide some comments. And one common comment for a user account is, obviously, the user name that we'll be using it, the person name. So, we'll use John Locke. That's the person that's going to be using this account. And we'll hit Enter to go ahead and create this account. Okay, that appears to have worked. Let's go ahead and create a couple of other accounts and then check out those accounts. So, let's do this. Let's do sudo, add local users. Let's use B Russell. Hit Enter. Great, we get a new password for this account. Doesn't match the other password. As a matter of fact, the password that you're going to see will not match either because it's being generated on the fly. Okay, we'll do one more account here. We'll make this say, an application account. So, those two people are philosopher names. Well, we'll pretend that this is going to be a philosophy application of some sort. And so, we'll just call this philapp and then we'll just use Philosophy Application User as the account description or the comment. Now, we've created three accounts. So, there should be three new entries in the /etc/passwd file So, one way to view the bottom portion of a file is with the tail command. The tail command is just more or less the opposite of the head command, which you're already familiar with. So, I'm just going to use tail -3 etc P-A-S-S-W-D. Sure enough, the first account we created has the proper username. John Locke as the comment, the same with the second one. And the third account we created, the application account had three words as the comment. And all three of those words have ended up in the /etc/passwd file So, it appears that our script is working as planned. By the way, you may see different account numbers depending on what accounts are on your system. For example, your J Locke user may have a UID of 1004 or 2000 or some other account depending on what you've previously done on the system and what other accounts exist and so on. So, don't be alarmed if it's not 100% exactly the same on your system as what is being displayed here. Let's go ahead and switch to an account and make sure that it's forcing a password change on login. So, I'm actually going to scroll up to find the password for the J Locke account. So the username J Locke and here's this big long password. I'm going to copy it. And then I'm going to go down here and switch user to the J Locke account. Now, it asks me for the password. I'm gonna paste it in. And now asks me for the current password. And now it's asking me for a new password. So, it indeed is changing the password on first login. So, let's use something here. Okay, I'm successfully switched to the J Locke account. You can see it's jlock@localusers. So, that looks right. Forced a password change when we first used the account. So, everything is looking good. So I'm just going to type in exit to get back to the Vagrant user. Now, we wanna make sure that the script exits with a non-zero exit status if the user does not use superuser privileges. So, let's just execute this command with out using sudo. And hit Enter, and it says, "Please run with sudo or as root. And then, so we can check the exit status with ${?}. Obviously, you can enclose that question mark in curly braces, but I'll just show you that you also don't have to do that. So, I'll just give you some variety here. So sure enough, one is not zero. So, that is exactly what we're looking for. And as a matter of fact, one is what we supplied as the exit code for the exit statement. Now, let's check for the other error condition which is we're executing the script as root but we didn't give a username. So, let's try that. We'll do sudo add-new-local-user.sh and hit Enter. And sure enough, it spits out our information here to teach the user how to use it. It tells them that they have to supply a username or otherwise this script is not going to work. And again, we'll look at the exit status and sure enough, it's one. So, everything is working as planned. All right, I'm done with this script and I'm actually done for the day. So, I'm going to log out of the Vagrant virtual machine and I'm actually going to halt it.

About the Author
Jason Cannon
Founder, Linux Training Academy
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 Amazon.com. 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