Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I learn BASH scripting occasionally from time to time, now I am working on a simple bash script that serves to maintain dove-cot user database. The general purpose of the script is able to list, add or delete user entries in the specified file. Please add some comments about the code - common mistake and etc... I want to learn more about code simplicity and avoiding bad habits.

#!/bin/bash

USERDB="/etc/dovecot/users"
MAILBOXMAP="/etc/postfix/virtual/virtual-mailbox-maps.cf"

## Add user function

add_user () {

# Reading username

while [[ -z "$USERNAME" ]]; do
    echo -n "Please enter username: "
    read "USERNAME"
done

# Reading domain name

while [[ -z "$DOMAIN" ]]; do
    echo -n "Please enter domain name: "
    read DOMAIN
done

# Reading password and generating hash with doveadm pw

while [[ -z "$PASSWORD" ]]; do
    echo -n "Please enter user password: "
    read "PASSWORD"
done

if [[ -n "$PASSWORD" ]]; then
    USERPASS="$(doveadm pw -p $PASSWORD -s SHA512-CRYPT)"
fi

# Adding provided credentials to Dovecot userdb

echo "Adding user credentials to userdb..."

echo "$USERNAME@$DOMAIN:$USERPASS:::" >> "$USERDB"

# Adding provided user@domain to postfix mailbox map

echo "Adding user credentials to postfix map..."

echo "$USERNAME@$DOMAIN $DOMAIN/$USERNAME" >> "$MAILBOXMAP"

# Hashing the map

if [[ -f "$MAILBOXMAP" ]]; then
     postmap hash://"$MAILBOXMAP"
     echo "Hashing map is done!"
else
     echo "Postfix map not exist or have been moved to another directory!"
     exit 1
fi
exit 0
}

## List all users function

list_users () {

if [[ -f "$USERDB" ]]; then
    awk -F: '/./'' {print $1} ' "$USERDB"
else
    echo "User database not exist or have been moved to another directory!"
    exit 1
fi
}

## Delete user function

delete_user () {
if [[ -n "$DELUSER" ]]; then
    sed -i "/^$DELUSER$/d" $USERDB $MAILBOXMAP && echo "User account have been  deleted!"
else
    echo "User not found!"
    exit 1
fi
}

case "$1" in
 add|-a)
    add_user
    ;;
 list|-l)
    list_users
    ;;
 delete|-d)
    shift
    deluser="$1"
    delete_user
    ;;
 *)
    echo "Unknown command"
    ;;
esac
share|improve this question

1 Answer 1

In this code:

while [[ -z "$USERNAME" ]]; do
    echo -n "Please enter username: "
    read "USERNAME"
done

What if the variable USERNAME is not empty when this code is reached? For example, the environment might be dirty by misbehaving scripts, and USERNAME might already be set to garbage, and the script will not prompt the user.

echo -n is not recommended because it's not portable. Use printf instead.

There's no need to quote USERNAME when reading into it.

The equivalent code, safer and better:

USERNAME=
while [[ -z "$USERNAME" ]]; do
    printf "Please enter username: "
    read USERNAME
done

Do similarly for the other loops too.


This will fail if PASSWORD contains spaces:

USERPASS="$(doveadm pw -p $PASSWORD -s SHA512-CRYPT)"

To make it safe, quote it:

USERPASS="$(doveadm pw -p "$PASSWORD" -s SHA512-CRYPT)"

It would be better to indent the function bodies. For example:

list_users () {
    if [[ -f "$USERDB" ]]; then
        awk -F: '/./'' {print $1} ' "$USERDB"
    else
        echo "User database not exist or have been moved to another directory!"
        exit 1
    fi
}

This is especially helpful in the case of longer functions.


The quotes are strange and confusing in this awk:

        awk -F: '/./'' {print $1} ' "$USERDB"

It would be better simply this way:

        awk -F: '/./ {print $1}' "$USERDB"
share|improve this answer
    
I mean any ideas about how to add feature "change user password" in script listed above? –  powerthrash Nov 28 '14 at 14:54
    
Similar to what you did in delete_user, you could use sed to replace the line with the user to change. And I suppose you'd have to rehash the $MAILBOXMAP file, but I don't know dovecot, so this is really just a guess. If you need more details, it would be better to ask on Stack Overflow. –  janos Nov 28 '14 at 15:41
    
I can't understand how to replace a set of characters between delimeters for exact lines with sed... Check this line for example (this is the part from dovecot userdb): [email protected]:{SHA512-CRYPT}$6$0vthg.LubtSCxRRK$MdTKNQ2Vk8ZW3XQXNXStt9rfr6fNa‌​XqPvZ0o9WJ8mW8y9ozE1pi8dYM8oQzwWa8ESGzEmJO6yT/tgi3ZEqAiE0::: How to replace the string starting with "{SHA512-CRYPT}" only for user "[email protected]" and not for user "[email protected]" with sed? p.s. The $MAILBOXMAP variable actually need only for Postfix. –  powerthrash Nov 28 '14 at 17:47
    
Or we have a much simplier but ugly solution - change the whole line with username and password. –  powerthrash Nov 28 '14 at 18:05
    
Such questions really belong on Stack Overflow, not this site. –  janos Nov 28 '14 at 18:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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