<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Toluwalemi Oluwadare</title>
    <description>The latest articles on Forem by Toluwalemi Oluwadare (@toluwalemi).</description>
    <link>https://forem.com/toluwalemi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F408991%2F5cb240b0-9ad9-40ea-b911-5feb6cc3e8d6.jpeg</url>
      <title>Forem: Toluwalemi Oluwadare</title>
      <link>https://forem.com/toluwalemi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/toluwalemi"/>
    <language>en</language>
    <item>
      <title>How To Create Users and Groups from a File Using Bash Script</title>
      <dc:creator>Toluwalemi Oluwadare</dc:creator>
      <pubDate>Thu, 04 Jul 2024 00:29:17 +0000</pubDate>
      <link>https://forem.com/toluwalemi/how-to-automate-user-creation-with-bash-script-3kkk</link>
      <guid>https://forem.com/toluwalemi/how-to-automate-user-creation-with-bash-script-3kkk</guid>
      <description>&lt;p&gt;This article explains how to create users and assign them groups and passwords from a given text file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Objectives&lt;/li&gt;
&lt;li&gt;Project Setup&lt;/li&gt;
&lt;li&gt;Bash Script&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you will be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create users with a bash script&lt;/li&gt;
&lt;li&gt;Create groups for these users&lt;/li&gt;
&lt;li&gt;Assign users to groups&lt;/li&gt;
&lt;li&gt;Generate and set passwords for users&lt;/li&gt;
&lt;li&gt;Log actions and manage permissions for security&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;.sh&lt;/code&gt; file named &lt;code&gt;create_users.sh&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;create_users.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create a text file named &lt;code&gt;sample.txt&lt;/code&gt; with user and group data.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;sample.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bash Script
&lt;/h2&gt;

&lt;p&gt;To get started, we first need to declare that this is a bash script using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line tells the system to use the bash shell to interpret the script.&lt;/p&gt;

&lt;p&gt;Next, we define our log file path and the password file path. This ensures we have paths to store logs and passwords securely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Define the log file and password file paths&lt;/span&gt;
&lt;span class="nv"&gt;LOGFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/log/user_management.log"&lt;/span&gt;
&lt;span class="nv"&gt;PASSWORD_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/secure/user_passwords.csv"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step ensures the script is run with root permissions. If you don't have the right permissions, the script will exit and inform you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Ensure the script is run with root permissions&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$EUID&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"This script must be run as root or with sudo"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;[[ $EUID -ne 0 ]]&lt;/code&gt; checks if the effective user ID is not zero (i.e., not root). The &lt;em&gt;effective user ID (EUID)&lt;/em&gt; represents the user identity the operating system uses to decide if you have permission to perform certain actions. If the &lt;code&gt;EUID&lt;/code&gt; is not zero, it means you're not running the script as the root user, and the script will print a message and exit with status 1.&lt;/p&gt;

&lt;p&gt;We then define a function to log actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Function to log actions&lt;/span&gt;
log_action&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOGFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes a message as an argument and appends it to the log file, also displaying it on the terminal.&lt;/p&gt;

&lt;p&gt;Let us create another function that will help us check if a group already exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;does_group_exists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;group_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;getent group &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        return &lt;/span&gt;0
    &lt;span class="k"&gt;else
        return &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the function returns a 0 then it means that the group exists. If it returns 1, then it means that it does not exist.&lt;/p&gt;

&lt;p&gt;Next, we check if the log file exists, create it if it doesn't, and set the correct permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if the log file exists, create it if it doesn't, and set the correct permissions&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOGFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOGFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  log_action &lt;span class="s2"&gt;"Created log file: &lt;/span&gt;&lt;span class="nv"&gt;$LOGFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;log_action &lt;span class="s2"&gt;"Log file already exists, skipping creation of logfile ' &lt;/span&gt;&lt;span class="nv"&gt;$LOGFILE&lt;/span&gt;&lt;span class="s2"&gt; ' "&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;[[ ! -f "$LOGFILE" ]]&lt;/code&gt; checks if the log file does not exist. If true, it creates the file and logs the action.&lt;/p&gt;

&lt;p&gt;We repeat a similar process for the password file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if the password file exists, create it if it doesn't, and set the correct permissions&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; SECURE_DIR
  &lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  log_action &lt;span class="s2"&gt;"Created password file: &lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;chmod &lt;/span&gt;600 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  log_action &lt;span class="s2"&gt;"Password file permissions set to 600: &lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;log_action &lt;span class="s2"&gt;"Password file already exists, skipping creation of password file: &lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the password file is created if it doesn't exist and sets the correct permissions for security.&lt;/p&gt;

&lt;p&gt;Next, we define a function to generate random passwords:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Function to generate random passwords&lt;/span&gt;
generate_password&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;password_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12
  &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-dc&lt;/span&gt; A-Za-z0-9 &amp;lt;/dev/urandom | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nv"&gt;$password_length&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;local&lt;/code&gt; keyword is used to define a variable that is local to the function. This means that the variable &lt;code&gt;password_length&lt;/code&gt; is only accessible with the &lt;code&gt;generate_passsword&lt;/code&gt; function, preventing it from interfering with other parts of the script.&lt;/p&gt;

&lt;p&gt;Let's break down what &lt;code&gt;tr -dc A-Za-z0-9 &amp;lt;/dev/urandom | head -c $password_length&lt;/code&gt; does, shall we?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;/dev/urandom&lt;/code&gt;: This is a special file in Unix-like systems that provides random data. It's often used for generating cryptographic keys, passwords, or any other data requiring randomness.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;tr -dc A-Za-z0-9&lt;/code&gt;: The &lt;code&gt;tr&lt;/code&gt; command is used to translate or delete characters. Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; tells &lt;code&gt;tr&lt;/code&gt; to delete characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c&lt;/code&gt; complements the set of characters, meaning it includes everything except the specified set.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;A-Za-z0-9&lt;/code&gt; specifies the set of allowed characters: uppercase letters (A-Z), lowercase letters (a-z), and digits (0-9).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;/dev/urandom&lt;/code&gt;: Redirects the random data from &lt;code&gt;/dev/urandom&lt;/code&gt; into the &lt;code&gt;tr&lt;/code&gt; command.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;code&gt;| head -c $password_length&lt;/code&gt;: The head command is used to output the first part of files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c $password_length&lt;/code&gt; specifies the number of characters to output, defined by the variable password_length (which is 12). This ensures the generated password is exactly 12 characters long.
This function uses &lt;code&gt;tr&lt;/code&gt; to generate a random string of 12 characters from &lt;code&gt;/dev/urandom&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We then define the &lt;code&gt;create_user_groups_from_file&lt;/code&gt; function, which creates a user and assigns groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;create_user_groups_from_file&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="c"&gt;# Check if the file exists&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"File not found: &lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;1
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c"&gt;# Read the file line by line&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# Remove whitespace and extract user and groups&lt;/span&gt;
    &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | xargs&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;groups&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;[[ ! -f "$filename" ]]&lt;/code&gt;: checks if the file exists. &lt;code&gt;-f&lt;/code&gt;: This is a file test operator. It checks if the provided path (in this case, stored in the variable &lt;code&gt;$filename&lt;/code&gt;) exists and is a regular file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;while IFS= read -r line; do ... done &amp;lt; "$filename"&lt;/code&gt;: reads the file line by line.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;username=$(echo "$username" | xargs)&lt;/code&gt;: extracts the username from the file. &lt;code&gt;xargs&lt;/code&gt; trims any leading or trailing whitespace and ensures that the result is treated as a single entity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;groups=$(echo "$groups" | tr -d ' ')&lt;/code&gt;: extracts the groups from the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let us add the logic to actually create the users and the groups.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;create_user_groups_from_file&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# ... previous code here&lt;/span&gt;

  &lt;span class="c"&gt;# Check if the user already exists&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# Create the user with a home directory&lt;/span&gt;
    useradd &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /bin/bash &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: Failed to create user &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;continue
    fi
        &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt; created."&lt;/span&gt;


 &lt;span class="c"&gt;# Generate a password and set it for the user&lt;/span&gt;
    &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;generate_password&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# and set password&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | chpasswd
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    log_action &lt;span class="s2"&gt;"Created user: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else
    &lt;/span&gt;log_action &lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt; already exists, skipping creation"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;

  &lt;span class="c"&gt;# Create a personal group for the user if it doesn't exist&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; does_group_exists &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        log_action &lt;span class="s2"&gt;"Successfully created group: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        log_action &lt;span class="s2"&gt;"User: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt; added to Group: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;log_action &lt;span class="s2"&gt;"User: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt; added to Group: &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Add the user to additional groups&lt;/span&gt;
  &lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; group_lst &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$groups&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;group &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;group_lst&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; does_group_exists &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="c"&gt;# Create the group if it does not exist&lt;/span&gt;
            groupadd &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            log_action &lt;span class="s2"&gt;"Successfully created Group: &lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;log_action &lt;span class="s2"&gt;"Group: &lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt; already exists"&lt;/span&gt;
        &lt;span class="k"&gt;fi&lt;/span&gt;
        &lt;span class="c"&gt;# Add the user to the group&lt;/span&gt;
        usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$group&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;done&lt;/span&gt;

  &lt;span class="c"&gt;# Set up home directory permissions&lt;/span&gt;
  &lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;chmod &lt;/span&gt;700 &lt;span class="s2"&gt;"/home/&lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$filename&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;if id "$username" &amp;amp;&amp;gt;/dev/null; then ...&lt;/code&gt;: This checks if the user exists then redirects both the standard output (stdout) and standard error (stderr) to &lt;code&gt;/dev/null&lt;/code&gt;. &lt;code&gt;/dev/null&lt;/code&gt; is a special device file that discards any data written to it. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;useradd -m "$username"&lt;/code&gt;: creates the user with a home directory. &lt;code&gt;-m&lt;/code&gt; flag tells &lt;code&gt;useradd&lt;/code&gt; to create a home directory for the user.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;groupadd "$username"&lt;/code&gt;: creates a personal group for the user.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;usermod -aG "$username" "$username"&lt;/code&gt;: adds the user to their personal group.&lt;code&gt;-a&lt;/code&gt; flag stands for "append". It tells &lt;code&gt;usermod&lt;/code&gt; to append the user to the specified group(s) without removing them from any other groups. On the other hand, &lt;code&gt;-G&lt;/code&gt; flag specifies that the following argument (&lt;code&gt;"$username"&lt;/code&gt;) is a list of supplementary groups which the user is also a member of.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IFS=',' read -ra group_lst &amp;lt;&amp;lt;&amp;lt; "$groups"&lt;/code&gt; splits additional groups by commas. Here the &lt;em&gt;Internal Field Separator&lt;/em&gt; (&lt;code&gt;IFS&lt;/code&gt;) means the shell will split strings into parts based on commas.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;groupadd "$group"&lt;/code&gt;: creates additional groups if they don't exist.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chown -R "$username":"$username"&lt;/code&gt;"/home/$username" sets the ownership of the home directory. &lt;code&gt;chown&lt;/code&gt; stands for change owner and the command recursively changes ownership for all files and subdirectories within &lt;code&gt;/home/$username&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chmod 700 "/home/$username"&lt;/code&gt; sets permissions of the home directory. &lt;code&gt;chmod&lt;/code&gt; stands for change mode and it changes file permission to 700. 7 grants read, write and execute permissions to the owner. 0 denies all permissions to others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;p&gt;To test the code simply run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash create_users.sh sample.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You can find the full code in my &lt;a href="https://github.com/Toluwalemi/hng-devops-stage-one-task"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[This article was written in completion of the &lt;a href="https://hng.tech/internship"&gt;HNG Internship&lt;/a&gt; stage one DevOps task. Learn more about the program &lt;a href="https://hng.tech/premium"&gt;here&lt;/a&gt;.]&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>bash</category>
      <category>linux</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
