4

I need to accept an email id and Full name in a script, and in case the Full name is not provided, I need to generate the name from the email id. Something like this:

Case 1:
EmailID: user.name@domainname.com
Full Name: User Name
Case 2:
EmailID: user.name2@domainname.com
Full Name: User Name2
Case 3:
EmailID: this.is.a.very.long.email.id@domainname.com
Full Name: This Is A Very Long Email Id

This I have been able to achieve using the following steps:

EMAIL_ADDRESS="$1"
ID=(`echo $EMAIL_ADDRESS | cut -d'@' -f1| tr '.' ' '`)
NEW_ID=()
NUM=0
for IN_VAL in ${ID[@]}
do
    NEW_ID[$NUM]="`echo ${IN_VAL^}`"
    NUM=$((++NUM))
done
echo "${NEW_ID[@]}"

I am on BASH version 4.1.2

I think there has to be a better way to achieve this. Also, I already see a problem in this as I am assuming the field separator is going to be dot (.) character and not anything else like underscore (_) or hyphen (-) or anything else. If there is a better way to do this, please let me know. Thanks.

  • Can it be sed? – heemayl Mar 28 '15 at 9:14
  • Yeah. That's what I wanted to know. any tool is fine. – AbhinavK Mar 28 '15 at 9:30
9

You can actually do this entirely in Bash, without any external commands, using word splitting and parameter expansion. It's even fairly short:

EMAIL_ADDRESS=this.is.a.very-long_email.id@domainname.com
USER=${EMAIL_ADDRESS%@*}
WORDS=( $(IFS=._- ; printf '%s ' $USER) )
echo "${WORDS[@]^}"

I'll take this line-by-line:

USER=${EMAIL_ADDRESS%@*}

This sets the USER variable to the part of EMAIL_ADDRESS that doesn't match @* at the end - that is, removing the domain name and leaving only the user part of the address.

WORDS=( $(IFS=._- ; printf '%s ' $USER) )

This creates an initialises an array WORDS. The initial values are given by the results of command substitution $(...).

Command substitutions run in a subshell, so we can change the values of variables safely without affecting their values in our main shell. That includes IFS, which is used during word splitting as the group of characters that cause a new word to begin. Each one of ., _, and - will form a word boundary, and you can add new characters there if you wish.

After changing IFS we use printf to print out the words $USER has been split into, which is a little safer than echo.

echo "${WORDS[@]^}"

Finally, we print out the result. The [@] is array expansion, as you know, and then ^ performs upper-casing of the first character in the word (strictly, the first match of the default pattern ?).

The final result of running this script is the output:

This Is A Very Long Email Id

as expected.


If any email addresses contain shell metacharacters *, ?, etc, they will be expanded as wildcards. You can wrap the WORDS= line in set -f / set +f to avoid that, but there's another option (courtesy of Glenn Jackman in the comments).

IFS=._- read -r -a WORDS <<<"${EMAIL_ADDRESS%@*}"
echo "${WORDS[@]^}"

This uses read -a to populate an array with the results of word splitting, and the rest (condensed) as before. I find this less clear to read than the explicit array initialisation, but it's an option.

It's also worth noting that email addresses can strictly have a wide variety of forms, including ones with spaces, quotes, and bracket characters in them, and this doesn't deal with those addresses at all (nor is it really possible to do so given your problem specification).

  • 1
    You can populate the words without a subshell: IFS=._- read -ra WORDS <<< "$USER" – glenn jackman Mar 28 '15 at 18:38
  • exactly what I wanted. Thanks a ton for the explanation. – AbhinavK Mar 30 '15 at 5:53
7

With sed:

sed 's/@.*//; s/[-_.]/ /g; s/\<./\U&/g' <<END
user.name@domainname.com
user.name2@domainname.com
this.is.a.very.long.email.id@domainname.com
END
User Name
User Name2
This Is A Very Long Email Id

Requires GNU sed for the \U upper case directive.

https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command

Expanded:

sed '
    s/@.*//        # remove @domain.name
    s/[-_.]/ /g    # translate dot,dash,underscore to spaces
    s/\<./\U&/g    # uppercase the first character of a word
                   # \< is a beginning-of-word marker
'

An inscrutable perl one-liner:

perl -nE's/@.*//;say"@{[map{ucfirst}/(\w+)/g]}"' 

Since perl's \w character class shortcut includes underscore,
this.is.a.very-long_email.id@domainname.com becomes
This Is A Very Long_email Id

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.