Linux Shell Scripting
The course is part of this learning path
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.
- 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
- 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.
At this point, you're almost ready to tackle your first project. There are just a couple of items left to cover. That's why in this lesson, you're going to learn how to get input from the person executing the script and how to create an account on a Linux system. As usual, I'm going to start up a terminal on my local system, go into our class folder. From there into the project folder that we're working on. And we've already have created the VMs. So I'm just going to run "vagrant up" to bring up that virtual machine. Now we'll connect to it. And we'll move into the shared folder of slash vagrant. This script, I'm going to call "luser-demo04.sh". So I'll go ahead and start my editor. And I will start out with a shebang like we should with every script we write. Now, Imma set the goal here, or intention for this script. So as you can see on your screen, the goal here is to create an account on the local system and whoever runs this script will be prompted for the account name and password. So the first thing we want to do is ask for the user's name. So I'm just going to create a comment here and leave that as a stub for us to go back and fill in, in just a minute. Then what we want to do is ask for the real name of the person who is going to be using this account that is going to be created. From there, we want to get the password. The next step would be to actually create the user. And then once we create a user, we need to set a password for that user using the password that was collected earlier. And finally what we want to do, is force that user to change their password the first time they log in. Up until this point, we've been working with scripts that can execute on their own without any external input or interaction with the person executing the script. Sometimes you're going to need information from the user in order for the script to do any meaningful work. In this specific example, you're going to ask the person who's running the script to supply a username and password for the account so that the script can go ahead and create that account. One way to get input from a user is by using the read shell builtin command which is what we're going to use in this script. Another way to get input from a user is to have them supply information on the command line, as arguments to your script. And you'll be learning about that method later on in the course. But for now, let's look at the read builtin. So, as you already know, you can use the type command to tell if a command as a shell builtin, or if it's an actual file on the file system. We do a "type read". It says, if you just execute, read then you'll get the read shell builtin. Again. If you want to see all the options here you can do dash A and the first option which is what's going to happen when you type in a command is run the shell builtin. Otherwise you can use the path to a file that's on your system in "/usr/bin/read". So, what we want to look at here is the shell builtin. So we're going to use the help builtin actually to get help on the read builtin. And I'm going to pipe this into less because I know there'll be a good bit of output that probably comes on the screen. You can tell what this command does by reading the first line of description. It says, "Read a line from the standard input and split it into fields" Now let's talk about input for a moment. There are actually three default types of input and output. They are standard input, standard output, and standard error. By default standard input comes from the keyboard, and standard output and standard error are displayed to the screen. And I'm using my words here carefully. I'm saying by default because as you're going to learn here in a few minutes, that standard input does not always have to come from the keyboard but typically that's where standard input comes from. And also goes on to talk about that the line will be split into fields and so on. And also says that any leftover words are assigned to the last name. And if you look at the end here you see name and these three periods or three dots or ellipses here that says you can specify multiple names. And what happens is each one of those will assign the value to a variable. So if you want to sign, assign an entire line of input to one variable, just supply one name or one variable name here at the end of the line. So that's what we're going to be using in this script. Also in our case, we want to display some text asking the user to supply us with some standard input from their keyboard. So if we go down here in the help, you'll see a dash P option and a prompt. So we can use dash P followed by a string which will act as a prompt. 'kay, Imma get out of this help here by hitting "Q". And let's do an example at the prompt. We'll use the read builtin with a dash P option which stands for a prompt. Then we're going to specify a string that will act as that prompt. Here I'm going to put a space at the end of this string so that when the user starts typing, they're not typing right at the end of that colon there, there's going to be a space. So now we want to store what they type into a variable and we'll just call this variable "THING", T-H-I-N-G and hit enter. So the read builtin executes, it displays the prompt of "Type something." And now I'm going to provide some standard input using my keyboard, and I'm literally going to type "something", and hit enter. Now the value of that I typed in there should be stored in the variable "THING". So let's check it out, echo thing and sure enough something comes back. Let's do this again. We'll just do the same command again and then type something else. So I'm gonna type, "Fred". So now we'll echo thing and sure enough, "Fred" is returned because "Fred" is the value that's stored in the variable named "THING". So this is how you can use the read builtin and we're gonna do this in our script. 'kay, we're gonna take the user input that we get and assign it to the variable called "USER_NAME". Okay, we'll just use this same technique for the real name of the user. And we're going to assign this input to the variable of "COMMENT" Okay one last read statement here. We're going to store this standard input in to the password variable. At this point in the script, we've gathered all the information from the person executing the script in order to be able to create an account. So let's go back to the command line here and look at the user add command, which we're going to use to create an account. If you look at the synopsis here on the man page for the user add command it says "useradd" followed by options which are in brackets, which as you know, are optional. And then it has a login at the end of the command. So that is required because it's not in brackets. Let's talk about logins. Now, the word login and username are the same thing, here in the documentation obviously they're using the term login. When I talk to you, or when I'm writing scripts I'll use usernames typically. In either case logins or usernames have some rules around them. Now, typically they are eight characters or less by convention. Now that's not a hard or fast rule but that's typically a convention or a practice that is followed. By the way this is something that you could check in your script if you want it to, or you can just display a warning if the username is over eight characters and we'll get the testing for string sizes in a future lesson, but that's just something to keep in the back your mind for now. So you might be asking, well why is there this eight character convention? The answer is that it's based on history. That used to be the maximum length back in old Unix systems. And of course the Linux was modeled after a lot of the Unix practices. And so we started using eight character usernames and a lot of commands such as "PS" and so on only display eight characters of username. So let's jump to the shell, create a username that has more than eight characters and see what happens. In order to add users to a system you need to use super user privileges. And one way we can do that is with a pseudo commands. We'll do "sudo useradd". We're going to leave off all those optional options and then create a long username. For example, I'm going to use "Doug Stamper" and hit enter. So now can switch to this user, again if we can use root privileges we won't have to specify a password. So we'll use "SU" space dash Doug Stamper and hit enter. By the way, the dash option to the "SU" command tells "SU" to start with an environment similar to that, of a real login. And also you can use "SU" dash L to get the same experience but either way "SU" dash or "SU" dash L will start a login shell, if you will. So now we're logged in here as Doug Stamper user, we can see our prompt has changed who Doug Stamper. So now what I'm going to do is look at the process table with the "PS" command "PS" dash E F to show every process. And then you can see here at the bottom that the two commands that are in the process table "bash" and "PS" dash E F are by the Doug Stamper username, but you can only see the first eight characters and when the username is longer than that in that field, you'll see a plus sign after it. So again, it's not something that's going to break anything. If you have a nine character a 10 character or a 20 character username it's just something to be aware of that some of these commands such as "PS" are going to give you a little bit different output because historically usernames are limited to eight characters. That's just something I want to point out here just in this conversation about creating scripts to create usernames. Going to exit out of Doug's shell here and get back to the vagrant user. By the way, username are case sensitive. So lowercase Doug is not the same user as capital D lowercase O U G. Again, you can do that. You can use uppercase letters but by convention they're in all lowercase. So it's a good practice to make sure your usernames are in all lowercase. Another thing to know is that you can't include any special characters in your username. However, you can use numbers. For example, if you're creating accounts using last names, and you have several people at your company that have the last name of Smith then you can do Smith one, Smith two Smith ninety nine, and so on, and those are all valid usernames. Let's get back to the man page and I want to point out one more thing to you here. There's an option to the user add command which is dash C that allows for a comment and that comment can be any string. Now, generally, it's a short description of the login and historically it's been used for a person's name. So if we make Smith one account and it's for Jane Smith then we would put Jane Smith in the comments. So we know what person is associated with that account. If the account is not for a person, then you can put in the application, that's going to use the account for example. Another thing I've seen done is when the account gets created, you put the name of the user in the comment field, along with a help desk ticket number and that can help for auditing purposes. For example, when you create Jane's account and it has help desk ticket, one, two, three you can go back and look at help desk ticket one, two, three, and said, "Oh, Jason was the Linux administrator that created that account." And then you can see, oh, Jane's manager approved that account, and then you can see who initiated that request from the help desk. So you have full accountability and a full chain of what happened and where that account came from. Okay. I know I said there was only one more thing I wanted to show you, but it turns out there was another thing I wanted to show you here. And I just thought of it. It's dash M option or dash dash create dash home. By the way, when you see that in the man page, two options here, one, a short form, dash M and another, a form dash dash create dash home. They both do the same thing and you only need to specify one or the other. For speed, a lot of times people use the shorthand name. If you want to be super clear you can use the long form name, the dash dash. But we're just going to stick to dash M here, when we use this to create our accounts. The dash M option here, as it says "Creates the user's home directory if it does not exist". It also goes on to say that the files and directories contained in the skeleton directory will be copied into the home directory. Traditionally that's "etc/skel", S K E L, but also here it says you can override that default with the dash K option. Continuing on, it says "by default, if this option is not specified and "CREATE_HOME" is not enabled, no home directories are created". So where's it getting this "CREATE_HOME" information from? Well, if you look into the configuration section of the man page, you're going to find out. Let's do that now. Do a forward slash for a forward search. Type in what I'm looking for and hit enter. And here we are at that section of the man page it says the "following configuration variables in /etc/login.defs change the behavior of this tool". And so that is the "CREATE_HOME" variable that we were talking about with the dash M option. So actually let's hit "Q" to get out of the man page and actually look at that file, "cat /etc/login.defs", and hit enter. And as you can see, they're three quarters a way up the top of your screen "CREATE_HOME" is set to yes. So if we were to not specify the dash M option the home directory would get created because of that is the default behavior. Something just to keep in mind and consider when you're writing shell scripts is that these default configurations may vary among different systems. So if you want to ensure, for example, a user home directory gets created, then use the dash M flag, and then you don't have to depend on this external configuration file. If you're in a controlled environment where you're sure all the "/etc/login.defs" files are the same then you can optionally leave that off. But if you want to be safe and force the creation of the home directory use of the dash M flag, and that's what I recommend. Okay, let's get back to our script and use what we learned about the user add command to actually create a user. So we'll use "useradd" dash C for a comment. Dash M to force the creation of a home directory. And then give it the username or login as it says in the man page. By the way, you may have noticed that I put the comment variable in quotes. The reason I did that is because this comment variable may contain spaces when we prompt them to enter the name of the person that the account is for, typically people have first and last names, if not more names. So someone will type in Jane space Smith. And that will be the information that is stored in that one comment variable. But again, there's a space. Now it's important to point out here by putting something in quotes, it gets treated as a single argument or a single item and not separate arguments or separate items. Okay, the next thing we need to do is set the password for the user and the command for that is "P A S S W D". Now let's get to the shell here and get some information about this command. By default, the password command spelled "P A S S W D" will prompt you to enter a new password for your account. To change a password for another account, you have to specify that account. Of course, only root can change other people's passwords. So let's just try the command out here on the command line for our current user. Type in "P A S S W D", and it prompts us for our current password. And then if we were to complete this process, then we could enter in a new password and our password would be changed. I'm just going to hit enter here and let it fail. So we need to come up with some sort of method to get around this interactive prompt. So let's dig into the man page and see if there is a way to supply the password non-interactively or in some programmatically or automated fashion. So "man passwd", and I'm gonna scroll down here dash K for keep, I don't think we need that, we're not looking to lock an account which is dash L or dash dash lock. Here we go, dash dash S T D I N. "This option is used to indicate that passwd should read the new password from standard input, which can be a pipe". So remember earlier that I said by default standard input comes from a keyboard. Well, standard input can also come from another command when it's used in what's called a pipeline. When you use a pipe symbol on a command line it means take the standard output from the proceeding command, the command that goes before the pipe and pass it as the standard input to the following command or the command that comes after the pipe. If the first command displays error messages, those will not be passed to the second command. Those error messages are called standard error output. You'll learn how to control standard error output later in the course. So we'll use this dash dash S T D I N option to set the password. We also want to force the user to change their password the first time they log in. To do that, we'll use the dash E option. As you can read the description here, it says "This is a quick way to expire a password for an account. The user will be forced to change the password during the next login attempt". Which is exactly what we want to do. Okay. Let's hit "Q" to get out of the man page and let's get back to editing our file. You already know how to use echo to create output. So we'll use echo to output the provided password and then use that output as standard input to the "PASSWD" command. So we'll echo the password, use a pipe, which again takes the output of the proceeding command which is echo takes that output and makes it the standard input for the following command which is "PASSWD". And as we learned by reading the man page we can use the dash dash S T D I N option to take standard input as the password. And so now, all's we have to do is tell the password command what user that this password belongs to. Finally, we need to force the user to change their password at first login. Again, as we learned in the man page we can use the dash E option. So P A S S W D dash E for expire user name and then we're good to go. Okay. Let's exit out of our shell script here save our changes and let's try it out. See if it works. Because this is the first time I'm going to be executing this script. I need to make sure it has the execute bit set on it. So I'm going to use the "chmond" command, "chomd" we can use, plus X for example, "luser-demo04.sh" that will work. You can also use the numeric notation of "chmod 755". I'll just use this for variety to show you another way to use the "chmod" command. Because we're adding a user with this script, we need to run this script with root privileges. So we'll use "sudo ./luser-demo04.sh" and hit enter. We've been talking about this person named Jane Smith. So let's give her an account. We'll call it J Smith and hit enter. The name of the person is Jane Smith and enter. And the password for the account, we'll use J Smith one, two, three. I know that's not very secure but we're gonna go with it for now. The output you see on your screen is from the "PASSWD" command which says changing the password for user J Smith and then also expiring the password for J Smith. Now, let's switch to the user and use their password. So we'll do "SU" space dash to act as a login shell and then the username J Smith. And this should prompt us for a password because we're not using root privileges or "sudo" because root can do anything, they can switch to any account without a password. But since this is the normal vagrant user that it's going to ask for the account password of this J Smith account because it doesn't know or doesn't trust this vagrant user. Okay, let's see if our password works J Smith one, two, three, hit enter, and sure enough we get prompted to change our password. So let's change it from J Smith one, two, three to something more interesting. Okay . Obviously I chose a poor password. Let me try something that is more secure. Okay. I've changed my account the first time I've logged in. So now the person that created account won't know their new password to the password that they're actually using going forward. And as you can look at the prompt, we have successfully changed to this account. Just type "exit" to log out of the J Smith account and get back to our vagrant account. Let's quickly recap some of the things we talked about during this lesson. First off you learned about the read shell builtin command which reads one line of standard input and stores it into a variable. From there, we looked at the user add command and you learn that the dash C option allows you to specify a comment for the account you're creating. Typically this comment will be the user's real name or other relevant information about the account. You also learned that the dash M option forces the creation of a home directory when creating an account. Next, you learned how to programmatically supply a password to the password command by piping the output of echo into the password command using the dash dash S T D I N option. Finally, you learn how to force a password reset for an account by using password with a dash E option followed by a username. At this point, you've learned all the concepts and techniques you'll need to create a script that adds users to a Linux system. Next up, you get to write that script.
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.