Exercise

Creating Users from a File Exercise

Task

You have been handed a list of new hires and asked to create an account for each of them. Write a script that reads the list line by line, reports what it did, refuses to run without root privileges, and is safe to run twice.

Host
servera
Script location
~/scripts/user_creator.sh
Input file
~/scripts/new_users.txt
  1. Stage the input file

    Create the scripts directory and write the list of accounts, one name per line. This stands in for a list handed to you by someone else.

    mkdir -p ~/scripts
    cd ~/scripts
    vim new_users.txt
    thufir_hawat
    lady_jessica
    paul_atreides
    cat new_users.txt
  2. Create an executable script

    vim user_creator.sh
    #!/bin/bash
    echo "Starting $0"
    chmod a+x user_creator.sh
    sudo ./user_creator.sh
  3. Read the file line by line

    A while read loop with input redirection processes one line per iteration.

    vim user_creator.sh
    #!/bin/bash
    while read -r new_user; do
        echo "Processing: $new_user"
        useradd "$new_user"
    done < "new_users.txt"
    sudo ./user_creator.sh

    Now run it a second time.

    sudo ./user_creator.sh

    Every useradd fails because the accounts already exist, but the script says Processing either way. The output is misleading.

  4. Report whether each account was created

    useradd returns 0 on success like any other command, so an if can branch on it directly.

    vim user_creator.sh
    while read -r new_user; do
        echo "Processing: $new_user"
        if useradd "$new_user"; then
            echo "User created."
        else
            echo "User NOT created."
        fi
    done < "new_users.txt"

    Add one more name to the list and run it again. The new account is created and the existing ones are reported honestly.

    echo "feyd_rautha" >> new_users.txt
    sudo ./user_creator.sh
  5. Refuse to run without root privileges

    EUID is the effective user ID of the running process. Root is always 0. Compare the two values yourself first.

    echo $EUID
    sudo bash -c 'echo $EUID'

    Add a guard immediately below the hashbang so the script stops before doing any work.

    vim user_creator.sh
    #!/bin/bash
    if [[ $EUID -ne 0 ]]; then
        echo "You must be root to run this script!"
        exit 9
    fi

    Without sudo the script now stops immediately with a clear message and a nonzero exit code, instead of failing halfway through.

    ./user_creator.sh
    echo $?
    sudo ./user_creator.sh
  6. Skip blank lines

    A stray blank line at the end of an input file is very common. Add one and watch what happens.

    vim new_users.txt
    sudo ./user_creator.sh

    The script tries to create an account with an empty name. Add a check at the top of the loop body: -z is true when a string is empty, and continue skips to the next iteration.

    vim user_creator.sh
    while read -r new_user; do
        if [[ -z "$new_user" ]]; then
            echo "Skipping empty line"
            continue
        fi
        echo "Processing: $new_user"
        if useradd "$new_user"; then
            echo "User created."
        else
            echo "User NOT created."
        fi
    done < "new_users.txt"
    sudo ./user_creator.sh
  7. Clean up

    Remove the accounts and their home directories so the host returns to its starting state, then delete the script and its input file.

    sudo userdel -r thufir_hawat
    sudo userdel -r lady_jessica
    sudo userdel -r paul_atreides
    sudo userdel -r feyd_rautha
    rm ~/scripts/user_creator.sh ~/scripts/new_users.txt
    cd ~