-1

Kinda stuck here, did not found any solutions.

Check If user exist in /etc/passwd, If exist create new one with prefix new_the_existed_one

#!/bin/bash

myuser="/home/yakyak/Desktop/Exercises/newusers.txt"

sed '/^[ \t]*$/d' $myuser | while read -r line
do
        name="$line"
        # adduser --disabled-login --gecos "" $name
        # check if user exist
        isthere=$(cut -d: -f1 /etc/passwd | grep "$name")

        # if user was added then make insert record into log file
        if [[ "$isthere" == "$name" ]]
        then
            echo "User already exist, creating new user.."
            adduser --disabled-login 
        # adduser --disabled-login --gecos " " $name
        fi   
done
muru
  • 69,900
  • 13
  • 192
  • 292
YakyAK
  • 13
  • 5
  • 1
    How does `newusers.txt` look like? Where exactly are you stuck - please try to describe your problem in more detail. In your script: what part does work well, where does it fail? – FelixJN Jan 27 '22 at 01:52
  • 2
    don't grep `/etc/passwd` directly, use `getent` instead. e.g. `getent passwd "$name" | cut -d: -f1`. Also, your `isthere` variable isn't needed at all, you can test the exit code of `getent` directly. `if getent passwd "$name" > /dev/null ; then ..... ; fi`. Or, if you insist on grepping /etc/passwd directly because you've never heard of `getent` before and it's confusing and scary: `if grep -q "^$name:" /etc/passwd ; then ... ; fi` but you shouldn't do that, you should learn the right tool for the job. – cas Jan 27 '22 at 04:23
  • 1
    BTW that `grep -q` should only be used if `$name` has been sanitised so that it doesn't contain any regex special characters like `.` or `*`. or use `grep -Pq "^\Q$name\E:" /etc/passwd` (using perl regex \Q and \E to disable regex metacharacters in $name). But you should still use getent instead of grepping /etc/passwd. – cas Jan 27 '22 at 04:28
  • What if the user does not exist - create one with name from `newusers.txt`? – RudiC Jan 27 '22 at 08:14
  • Thanks everyone for your assistance I have a text file with users under the name newusers.txt, I want to check if the user exist in /etc/passwd, If the user exist create a new user with new_existed_username, Struggling with this. – YakyAK Jan 27 '22 at 09:44

1 Answers1

1
#!/bin/bash

NAME_REGEX='^[a-z][-a-z0-9]*$'   # default value for adduser.conf
. /etc/adduser.conf              # "source" it in case local config is different

myuser='/home/yakyak/Desktop/Exercises/newusers.txt'

grep "$NAME_REGEX" "$myuser" | while read -r name; do
  while getent passwd "$name" > /dev/null; do
    name="new_$name"
  done

  # check if $name is > 32 characters
  if [ "${#name}" -gt 32 ] ; then
    echo "username '$name' is too long" > /dev/stderr
  else
    adduser --disabled-login --gecos '' "$name"
  fi
done

Instead of using sed to delete empty lines from your newusers.txt file, it uses grep to exclude invalid usernames, those which don't match a pattern stored in a shell variable called $NAME_REGEX. It uses the same variable name (and regex pattern) as adduser itself for the definition of "valid". See man adduser.conf and search for NAME_REGEX.

This will keep on pre-pending "new_" to $name until $name doesn't exist in the passwd db. If "user" exists, it'll try "new_user". if "new_user" exists, it'll try "new_new_user". and then "new_new_new_user". and so on.

The script uses getent passwd, but only cares about the exit code - the output is discarded (redirected to /dev/null). If getent exits with 0 (true), then the user exists, so try again.

When getent returns false (i.e. $name doesn't already exist), it checks if the name is too long. If it is, it prints an error message. If it isn't, it runs adduser.

BTW, the actual exit code we expect to see from getent is 0 for if the user already exists and 2 if the user does not exist. In some circumstances, getent can return different exit codes (see man getent), but they're not possible with the way we're using getent (i.e. searching the passwd db AND providing a username).


A slightly better version would be to use a numeric suffix for the usernames. e.g. using printf with a %03i format string for a 3-digit wide zero-padded number (e.g. 001, 002, etc). If you don't want it zero-padded, use %i instead. The count variable is reset to zero in the outer while loop for each username processed.

#!/bin/bash

NAME_REGEX='^[a-z][-a-z0-9]*$'   # default value for adduser.conf
. /etc/adduser.conf              # "source" it in case local config is different

myuser='/home/yakyak/Desktop/Exercises/newusers.txt'

grep "$NAME_REGEX" "$myuser" | while read -r user; do
  name="$user"
  count=0

  while getent passwd "$name" > /dev/null; do
    let count+=1
    name="$(printf "%s%03i" "$user" "$count")"
  done

  # check if $user is > 32 characters
  if [ "${#name}" -gt 32 ] ; then
    echo "username '$name' is too long" > /dev/stderr
  else
    adduser --disabled-login --gecos '' "$name"
  fi
done

This version uses two variables for the username - $user for the name as read in from the newusers.txt file, and $name for the current username we're trying to use. $name is initially copied from $user, and the inner while loop updates $name by incrementing the $count variable and appending it to $user whenever getent returns true.


Finally, neither of the above are particularly good scripts. They do little more than the bare minimum required. Personally, I'd be inclined to write it in perl rather than bash because text processing in shell is a PITA.

cas
  • 1
  • 7
  • 119
  • 185