I need to create a Bash script to remove a user.
We use RHEL version 4, 5, & 6.
Lets say usernames are Ray4 & Ray6 & the script name is deal.
Specific tasks for this script are:

  1. Does the user exist ?
  2. If user exists, backup /homedirectory for this user, remove username and place in /root/DeletedUsers
  3. If /root/DeletedUsers directory doesn't exist, create it.
  4. If any firewall rules exist for this user, email me the results for those rules and on which nodes.
  5. If this user exists in sudoers, don't delete, but comment out.

This is what I have so far. I want to make sure this works, before I run it in RHN Satellite. After making the suggested changes. Here are the new errors I am getting now.

[root@localhost bin]# ./deal
./deal: line 7: [[!: command not found
Usage: userdel [options] LOGIN

  -f, --force                   force removal of files,
                                even if not owned by user
  -h, --help                    display this help message and exit
  -r, --remove                  remove home directory and mail spool
  -Z, --selinux-user            remove SELinux user from SELinux user mapping

Usage: userdel [options] LOGIN

  -f, --force                   force removal of files,
                                even if not owned by user
  -h, --help                    display this help message and exit
  -r, --remove                  remove home directory and mail spool
  -Z, --selinux-user            remove SELinux user from SELinux user mapping

Null message body; hope that's ok
./deal: line 22: [: -me: binary operator expected

This is source code:
[root@localhost bin]# cat -n deal

 1  #!/bin/bash
 3  count=$(egrep -c Ray[46] /etc/passwd)
 4  firewall=$(grep -c "" /etc/sysconfig/iptables)
 5  doers=$(egrep -c Ray[46] /etc/sudoers)
 7  if [[! -d /root/DeletedUsers]]
 8  then mkdir /root/DeletedUsers
10  fi
12  cp -Rf /home/Ray[46] /root/DeletedUsers
13  userdel -rf Ray [4]
14  userdel -rf Ray [6]
16  if [ $firewall -ne 0 ]
18  then mail -s "$firewallrulesexist" emailaddress < /dev/null
20  fi
22  if [ $doers -me 0 ]
23  then sed ^Ray[46] /#/i
25  EOF
26  fi
  • Change if [[ $firewall -ne 0 ]] to if [ $firewall -ne 0 ]. And similarly, change if [[ $doers -me 0 ]] to if [ $doers -ne 0 ].
    – Ramesh
    Apr 25 '14 at 14:53
  • And where are you creating the DELETED USERS directory? If it is under current directory, then no need of ` and also use "` to create the directory. Something like, mkdir "DELETED USERS".
    – Ramesh
    Apr 25 '14 at 14:56
  • Also, change -count to -d in if [[! -count /Deleted_Users]]
    – Creek
    Apr 25 '14 at 15:13
  • 1
    Instead of [[! -d /root/DeletedUsers]] you want ! [ -d /root/DeletedUsers ]. Or, honestly, if you use mkdir -p, that won't error if it already exists, so you can omit the test.
    – derobert
    Apr 25 '14 at 16:17
  • 3
    You don't need a bash script. You need a central point of identity management and/or a configuration management system.
    – dawud
    Apr 25 '14 at 16:18

I would suggest you use getent to check for the existence of an user. This script should get you going.

##Check if the user exists using getent command
user_exists=$(getent passwd $1)

##If the user doesn't exist, we need not perform the backup. 

if [ -z "$user_exists" ] 
        echo "User $1 does not exist"
        cd /root
        #Incorporating derobert's suggestion here. 
        mkdir -p "DeletedUsers"
        ##Use tar or rsync to do the backup as cp will be inefficient.
        tar czvf "$1".tar.gz /home/"$1"
        firewall=$(grep -c "" /etc/sysconfig/iptables)
        doers=$(egrep -c "$1" /etc/sudoers)
        userdel -rf "$1"
        if [ $firewall -ne 0 ]
            mail -s "$firewallrulesexist" emailaddress < /dev/null
        if [ $doers -ne 0 ]
            sed ^"$1" /#/i

You can call the script as ./deal ray[4] and then if you need to run for another user you can call it using ./deal ray[6]. I have not tested the script in my system, but this should help you out as in case if you need to delete any other user in future, you need not modify the script but rather call the script with the username as an argument.


As per derobert's suggestion, you can omit directory testing if you use -p flag.


If Ray[46] is assuredly unique, pretty much every test in your script is redundant.

printf %s\\n 123 456 | sed '/2/s///'


The above will scan its input for any line containing the /addressed/ string 2, and, if found, will change only that line to contain everything but the addressed string. The following simply deletes only addressed lines:

printf %s\\n 123 456 | sed '/2/d'


So grep then sed is not necessary. True, grep is faster than sed, but in the time it takes to invoke grep and [test] its output then invoke sed, sed would likely already have finished clearing all concerned files of the offending string.

Then again, if you do want to grep then sed for whatever reason, the following would be much more to the point:

remove=string ; for f in $(grep -l "$remove" $file_list) ; do 
    printf %s "$(sed "/$remove/s///" "$f")" >"$f" ; done

Or with GNU sed :

sed -i "/$remove/s///" $(grep -l "$remove" $file_list)

And as mentioned above, mkdir -p makes a target directory only if necessary, so this should suffice:

mkdir -p /root/DeletedUsers ; mv /home/$string "$_"

You could even get a log of it all to review exactly what was done on only those machines something occurred:

#ensure $tgt dir exists
mkdir -p ${tgt=/root/DeletedUsers}
#handles Ray4 and Ray6 cases on a single machine
for remove in /home/Ray[46] ; do hostname #print hostname
#nothing happens unless user's $HOME exists
    cd "$remove" 2>/dev/null || { 
        echo "No $remove found here."
#get out of user's $HOME and mv it
    cd - ; mv -v "$remove" "$tgt"
#strip $remove to only username then userdel it
    userdel -rf $remove
#if $remove in /etc/sudoers comment file's line and and copy change to stderr
    sed -nei "/$remove/{!p;b};s/^/#/p" /etc/sudoers \
        -ne "s/^/sudoers change: /w /dev/stderr" 
#print all iptables lines containing string $remove
    grep "$remove" /etc/sys/config/iptables |
#for each rule found append a noticeable marker line
        sed "a--- "$(hostname)"firewall found"
#finish for statement and pipe all to remote cat to append to log    
done 2>&1 | ssh you@host 'cat >>~/Raydel.log'

That above assumes your target user has a $HOME in /home named for the user's username. If the assumption is correct, it only takes action on any machine on which the target user's username is registered.

To do the same without grep you can leave tee out as well. Just change the sed line to:

for f in $file_list ; do 
    sed -ni "/$remove/{h;s///};p;\$!b;x;/$remove/s|.*|$f|w /dev/stderr" "$f"

That will overwrite sed's holdspace with each new line sed finds containing the string "$remove". When sed's through scanning and gets to the last line it switches to the holdspace, and, if it finds any references to $remove it writes the filename to stderr.

If you run a script like the one I wrote above from your own machine and you ssh out to all of the targets then you don't have to open an ssh connection from each of them back to your own machine - you're already there. You could remove the last |pipe and everything following it and do this instead:

script=$(cat <<\SCRIPT
#body of the script I wrote above less the |pipe and all that followed
for host in $hosts ; do ssh you@$host "$script" ; done >>~/Raydel.log

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.