2

I have a project that consists of adding users to the OS and these users are in a text file. I have written this so far but it isn't working. Can you tell me what's wrong?

The file user.txt is:

charbel:password:1001:1001:Charbel Haddad:/home/charbel:/bin/bash:0:30:15:7:y
assil:p@ssw0rd:1002:1002:Assil:/home/assel:/bin/bash:0:30:10:5:n
marwan:p@ssw0rd:1003:1003:Marwan Ghantous:/home/marwan:/bin/bash:0:50:30:7:n
michel:password:1004:1004:Michel:/home/michel:/bin/bash:1:30:10:5:y

Script:

FILE="user.txt"

USERNAME=$(cut -d " " -f 1 $FILE)
PASSWORD=$(cut -d " " -f 2 $FILE)
USER_ID=$(cut -d " " -f 3 $FILE)
GROUP_ID=$(cut -d " " -f 4 $FILE)
USER_INFO=$(cut -d " " -f 5 $FILE)
HOME_DIRECTORY=$(cut -d " " -f 6 $FILE)
SHELL=$(cut -d " " -f 7 $FILE)
MIN=$(cut -d " " -f 8 $FILE)
MAX=$(cut -d " " -f 9 $FILE)
INACTIVE=$(cut -d " " -f 10 $FILE)
WARNING=$(cut -d " " -f 11 $FILE)

useradd -m -c "${USERNAME}" "${PASSWORD}" "${USER_ID}" "${GROUP_ID}" "${USER_INFO}" "${HOME_DIRECTORY}" "${SHELL}" "${MIN}" "${MAX}" "${INACTIVE}" "${WARNING}"
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Have you done any debugging? For example, did you print out the variable values to check whether they are what you expect? – kaylum Dec 14 '20 at 20:43
  • Please add user.txt to your question (no links, no comment). – Cyrus Dec 14 '20 at 20:45
  • In what way isn't it working? Does `user.txt` contain just one line of data? What do you get from `echo "[[$USERNAME]]"` before the `useradd` command? – Jonathan Leffler Dec 14 '20 at 20:45
  • Which distribution and version do you use? – Cyrus Dec 14 '20 at 20:48
  • @JonathanLeffler there are actually 4 lines of data each line consisting of a user with its fields – Elena Assaf Dec 14 '20 at 20:49
  • This question belongs on [Unix & Linux](http://unix.stackexchange.com/tour) in the Stack Exchange network. – Cyrus Dec 14 '20 at 20:50
  • 2
    @Cyrus: no — this is about shell programming and is on topic for Stack Overflow. – Jonathan Leffler Dec 14 '20 at 20:50
  • @JonathanLeffler: no — this is about syntax of `useradd` and not shell programming. – Cyrus Dec 14 '20 at 20:51
  • @ElenaAssaf — then you get output like `[[user1` – `user2` – `user3` – `user4]]` from the echo command I gave (where the dashes represent newlines — you can't format comments very much). That shows you what the problem is, does it not? – Jonathan Leffler Dec 14 '20 at 20:51
  • @Cyrus — this is about the use of `cut` on a multi-line file and the values stored in the shell variables of the shell ***program*** that the OP is trying to write. The semantics of `useradd` are coincidental to the issue. – Jonathan Leffler Dec 14 '20 at 20:52
  • @ElenaAssaf: add the `user.txt` file to the question where it can be formatted. Why are you specifying space as the delimiter between fields in the `cut` commands when the file uses colons? You're going to need a variant on `while read -r line; do …processing of one line…; done < user.txt`. Or you might futz with `IFS` to split the lines on colons and use `read -r USERNAME PASSWORD … WARNING`. – Jonathan Leffler Dec 14 '20 at 20:54
  • See also [How to debug a shell script?](https://stackoverflow.com/a/951352/15168) – Jonathan Leffler Dec 14 '20 at 20:57
  • 1
    There's your problem; your fields in the file are `:` delimited, but you're telling `cut` to use **space** as a delimiter. – tink Dec 14 '20 at 20:59
  • @tink so i just have to put ":" instead of " " ? – Elena Assaf Dec 14 '20 at 21:00
  • 1
    Using `cut` also makes each variable a *list* of values. You want to split each line separately, using `read`. – chepner Dec 14 '20 at 21:00
  • That will **cure** the immediate issue; there may be, as @Cyrus pointed out, problems with the way you use `useradd` as well ... – tink Dec 14 '20 at 21:03
  • While shellscripting is clearly about programming, it matches much better the https://unix.stackexchange.com . – peterh Dec 18 '20 at 11:42

1 Answers1

0

Independently of any issues related to the invocation of useradd, there are multiple problems in the way you're extracting the data from the data file:

  1. The field separator in the file is a colon, but you use cut -d " " to split on spaces.
  2. When you process a file with 4 lines, the value in $USERNAME will contain 4 names, one per line.

To read the data, I recommend setting IFS=: and using read in a loop to read the fields and process the results. You might end up with a script a bit like this:

#!/bin/bash

IFS=:
while read -r usename password user_id group_id user_info home shell min max inactive warning
do
    echo useradd -m -c "$usename" "$password" "$user_id" "$group_id" \
         "$user_info" "$home" "$shell" "$min" "$max" "$inactive" "$warning"
done < data

It would probably be best to leave the < data out of the script, or use cat "$@" | while read … so that data can come from other places than just the file data. Given your input, the output is:

$ bash script.sh
useradd -m -c charbel password 1001 1001 Charbel Haddad /home/charbel /bin/bash 0 30 15 7:y
useradd -m -c assil p@ssw0rd 1002 1002 Assil /home/assel /bin/bash 0 30 10 5:n
useradd -m -c marwan p@ssw0rd 1003 1003 Marwan Ghantous /home/marwan /bin/bash 0 50 30 7:n
useradd -m -c michel password 1004 1004 Michel /home/michel /bin/bash 1 30 10 5:y
$

Now, whether that's a valid invocation of useradd that is being echoed is another question altogether, but at least the right data is being processed.

Judging from the man page for useradd on RHEL 7.4 (it happens to be the convenient Linux system I have access to), the invocation is badly malformed. The values mostly need to be prefixed by an option, such as --comment or -c for the 'comment' field, which is in the $user_info variable specified above. AFAICS, the user name should go last, without a specific option prefix. But the critical part is reading the data.

Running useradd --help as root yields:

Usage: useradd [options] LOGIN
       useradd -D
       useradd -D [options]

Options:
  -b, --base-dir BASE_DIR       base directory for the home directory of the
                                new account
  -c, --comment COMMENT         GECOS field of the new account
  -d, --home-dir HOME_DIR       home directory of the new account
  -D, --defaults                print or change default useradd configuration
  -e, --expiredate EXPIRE_DATE  expiration date of the new account
  -f, --inactive INACTIVE       password inactivity period of the new account
  -g, --gid GROUP               name or ID of the primary group of the new
                                account
  -G, --groups GROUPS           list of supplementary groups of the new
                                account
  -h, --help                    display this help message and exit
  -k, --skel SKEL_DIR           use this alternative skeleton directory
  -K, --key KEY=VALUE           override /etc/login.defs defaults
  -l, --no-log-init             do not add the user to the lastlog and
                                faillog databases
  -m, --create-home             create the user's home directory
  -M, --no-create-home          do not create the user's home directory
  -N, --no-user-group           do not create a group with the same name as
                                the user
  -o, --non-unique              allow to create users with duplicate
                                (non-unique) UID
  -p, --password PASSWORD       encrypted password of the new account
  -r, --system                  create a system account
  -R, --root CHROOT_DIR         directory to chroot into
  -s, --shell SHELL             login shell of the new account
  -u, --uid UID                 user ID of the new account
  -U, --user-group              create a group with the same name as the user
  -Z, --selinux-user SEUSER     use a specific SEUSER for the SELinux user mapping

You would use the -K option with appropriate values to specify the minimum and maximum days between password changes.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278