Bulk create Linux users from a file (`useradd`, passwords, Ubuntu onboarding)

Onboarding-style Bash: read usernames from a file, create multiple Linux users with useradd, optional custom shell and home under /home, per-user passwords with chpasswd, force change on first login, and test with su or sudo -u.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Bulk create Linux users from a file (`useradd`, passwords, Ubuntu onboarding)

If you need a linux bulk users onboarding script—read a list, create accounts, set shells and home trees, then hand out shell password material once—useradd plus chpasswd is the usual server approach on Debian and Ubuntu. Desktop distros often teach adduser, but adduser is interactive; for how to create multiple users in linux from a file, useradd stays predictable in loops. Read how to create a user in Linux, useradd, and adduser first if the basics are new.

Shell syntax below was checked with bash -n on Ubuntu 25.04, Bash 5.2.37. I did not execute useradd / chpasswd in this environment (they need root and real accounts); run on a VM or container you can throw away.


Input file: list of usernames (stub-friendly format)

Put one username per line, optional comments with #, blank lines ignored. This matches the “read the list of … users” part of long onboarding prompts:

text
# usernames.txt
ravi_kumar
anjali_gupta
amit_patel

Usernames should match ^[a-z_][a-z0-9_-]*$ (POSIX account name rules); reject anything else so a typo does not break useradd.


Simple create user script (homes with -m)

bash
#!/usr/bin/env bash
set -euo pipefail

if [[ $(id -u) -ne 0 ]]; then
  echo "Run as root (or sudo ./script)" >&2
  exit 1
fi

user_file=${1:-usernames.txt}
[[ -f "$user_file" ]] || { echo "Missing $user_file" >&2; exit 1; }

while IFS= read -r line || [[ -n "$line" ]]; do
  line=${line//$'\r'/}
  [[ -z "${line// }" || "$line" =~ ^[[:space:]]*# ]] && continue
  u=${line%%[[:space:]]*}
  if [[ ! "$u" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]]; then
    echo "skip invalid name: $u" >&2
    continue
  fi
  if id "$u" &>/dev/null; then
    echo "exists: $u"
    continue
  fi
  useradd -m -c "bulk,$u" "$u"
  echo "created: $u"
done <"$user_file"

-m creates /home/$u with skeleton files. Adjust /etc/skel on Ubuntu if you need default dotfiles for onboarding.


Custom shell and home directory (useradd -d / -b)

Pick a shell that exists on the image (often /bin/bash). If every home must live under a shared prefix, set BASE and pass -d explicitly—avoid the earlier bug pattern of using $home_base before defining it.

bash
#!/usr/bin/env bash
set -euo pipefail
[[ $(id -u) -eq 0 ]] || exit 1

user_file=${1:-usernames.txt}
shell_bin=/bin/bash
base=/srv/homes

mkdir -p "$base"

while IFS= read -r line || [[ -n "$line" ]]; do
  [[ -z "${line// }" || "$line" =~ ^[[:space:]]*# ]] && continue
  u=${line%%[[:space:]]*}
  [[ "$u" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || continue
  id "$u" &>/dev/null && continue

  useradd -m -d "$base/$u" -s "$shell_bin" -c "bulk,$u" "$u"
  echo "created $u -> $base/$u"
done <"$user_file"

Per-user password, chage, and a secrets file (better than echoing)

For shell password setup without pasting into chat logs:

  1. Generate one secret per user (example uses openssl).
  2. Pipe username:password lines to chpasswd.
  3. Write the same pairs to a root-only file (mode 600), not to stdout.
  4. Run chage -d 0 so Linux forces a change at first login.
bash
#!/usr/bin/env bash
set -euo pipefail
[[ $(id -u) -eq 0 ]] || exit 1

user_file=${1:-usernames.txt}
secrets=/root/bulk-onboarding-$(date +%F).txt
: >"$secrets"
chmod 600 "$secrets"

while IFS= read -r line || [[ -n "$line" ]]; do
  [[ -z "${line// }" || "$line" =~ ^[[:space:]]*# ]] && continue
  u=${line%%[[:space:]]*}
  [[ "$u" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || continue
  id "$u" &>/dev/null && continue

  pw=$(openssl rand -base64 18)
  useradd -m -s /bin/bash -c "bulk,$u" "$u"
  printf '%s:%s\n' "$u" "$pw" | chpasswd
  printf '%s\t%s\n' "$u" "$pw" >>"$secrets"
  chage -d 0 "$u"
  echo "created $u (password recorded in $secrets)" >&2
done <"$user_file"

Deliver $secrets through your org’s vault or out-of-band channel—never commit it to git.

Using one random password for every user (an older pattern) is weak; prefer per-user secrets as above.


How to switch user in Linux using a shell script (testing)

After creation, operators usually verify with an interactive shell:

  • su - username — classic; prompts for that user’s password.
  • sudo -u username -i — handy if root’s sudoers allows it; still interactive for a login shell.

Fully non-interactive “switch user” inside a script for password auth is painful (expect is brittle). Prefer sudo -u user command … to run one command as the new account during automation instead of scripting su passwords.


Summary

How to create multiple users in linux from a file: loop with useradd -m, validate names, skip existing id. A solid create user script adds -s and -d when homes leave /home. For shell password handling, feed chpasswd with openssl-generated secrets, store them in a 600 file, and use chage -d 0 for first-login rotation. For how to switch user in linux using shell script workflows, use sudo -u for single commands; reserve su - for manual checks. Treat any bulk onboarding script as sensitive: dry-run on a VM, read man useradd / man chpasswd, and align with your distro’s defaults on Ubuntu and elsewhere.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …