2

This is what I have. I am trying to validate 3 inputs. The first and the second inputs do not ask me to enter the correct input. What is wrong?

#!/bin/bash                                                                     
while :                                                                         
        do                                                                      
        echo "Please enter your tittle:"                                        
        read TITTLE                                                             
        echo "Please enter your surname:"                                       
        read SURNAME                                                            
        echo "Please enter your ID No."                                         
        read ID                                                                 

        if [ "$TITTLE" = "" ] || [ "${TITTLE//[!0-9]}" != "" ];                 
        then                                                                    
        echo "Enter your valid tittle without special characters."              
        echo "Please try again."                                                
        exit 1                                                                  
        fi                                                                      

        if [ "$SURNAME" = "" ] || [ "${SURNAME//[!0-9]}" != "" ];               
        then                                                                    
        echo "Enter your valid surname without special characters."             
        echo "Please try again."                                                
        exit 1                                                                  
        fi                                                                      

        if [ "$ID" = "" ] || [ "${ID//[0-9]}" != "" ];                          
        then                                                                    
        echo "Enter your valid ID No. without special characters."              
        echo "Please try again"

        else                                                                    
        echo "Thank you" $TITTLE $SURNAME                                       
        break                                                                   
fi                                                                              
done        
  • 1
    First step, paste it into shellcheck.net and address its concerns. Then please do come back here with specifics. – roaima Mar 10 at 7:30
  • I tried your script, and it works and validates input as expected – David Mar 10 at 7:31
  • 1
    Second step, remember that exit exits from the script entirely. To restart a loop you might want continue. To break from a loop you might want break – roaima Mar 10 at 7:33
  • 1
    @David try entering nothing for either the title or surname – roaima Mar 10 at 7:33
  • 2
    Fourth step, particularly because you're referring to "special characters", please edit your question to show example input, and any errors or other output that you get in response. Finally, show us what you want to happen - but doesn't yet. – roaima Mar 10 at 7:36
3

Your script exits as soon as invalid input is given for the title or surname, which renders the loop useless. Use continue to re-do an iteration.

However, you don't want to force the user to enter their title and surname again only because they entered an invalid ID, so you will need three input loops rather than one big loop; one loop for each thing that you read from the user.

Your code is needlessly repetitive, and rewriting it as three loops would also be needlessly repetitive. It would be more convenient to have a separate input function.

In the following script I've done that. The input function get_input takes a "label" (some description of what the user should enter) and a pattern that each character in the input must match. The get_input function outputs the valid string on standard output, which is why we call it within a command substitution in the main part of the script.

I have also moved the string validation to its own function. This is to make the get_input function cleaner and to separate the validation logic from the input logic.

The validation uses the same approach as you use, i.e. it deletes all characters from the string that are valid and then tests whether there are any characters left, in which case the string fails the validation.

#!/bin/bash

# Succeeds if the first argument is non-empty and only
# consists of characters matching the pattern in the
# second argument.
is_valid () {
        local string pattern

        string=$1
        pattern=$2

        [ -n "$string" ] && [ -z "${string//$pattern}" ]
}

# Asks user for input until the given string is valid.
# The first argument is a text string describing what
# the user should enter, and the second argument is a
# pattern that all characters in the inputted data much
# match to be valid.
get_input () {
        local label pattern
        local string

        label=$1
        pattern=$2

        while true; do
                read -r -p "Please enter $label: " string

                if is_valid "$string" "$pattern"; then
                        break
                fi

                # Complain on the standard error stream.
                printf 'Invalid input, try again\n' >&2
        done

        printf '%s\n' "$string"
}

# Get data from user.
title=$(   get_input 'your title'   '[[:alpha:] ]' )    # title: only letters and spaces
surname=$( get_input 'your surname' '[[:alpha:] ]' )    # surname: same as title
id=$(      get_input 'your ID no.'  '[[:digit:]]' )     # ID: only digits

# Print what we got.
printf 'Title   = "%s"\n' "$title"
printf 'Surname = "%s"\n' "$surname"
printf 'ID      = "%s"\n' "$id"

To also allow e.g. dots in the title or surname, change the pattern from [[:alpha:] ] to [[:alpha:]. ]. Or, you can be even less restrictive and use [![:digit:]] to allow any non-digit character (including punctuation marks etc.)

To save the output in a file with the same name as the user running the script, redirect the output of the script itself:

$ ./script.sh >"$USER.txt"

This would run the script and redirect the output to a file called $USER.txt, where $USER is the username of the current user (this variable, and $LOGNAME, are usually already set by the shell and/or the system).

You could also do this within the script itself by changing the last three printf lines into

# Print what we got.
{
    printf 'Title   = "%s"\n' "$title"
    printf 'Surname = "%s"\n' "$surname"
    printf 'ID      = "%s"\n' "$id"
} >"$USER.txt"

Or, if you want to use the "surname" read from the user in the script:

# Print what we got.
{
    printf 'Title   = "%s"\n' "$title"
    printf 'Surname = "%s"\n' "$surname"
    printf 'ID      = "%s"\n' "$id"
} >"$surname.txt"

To also print to the terminal, use tee:

# Print what we got.
{
    printf 'Title   = "%s"\n' "$title"
    printf 'Surname = "%s"\n' "$surname"
    printf 'ID      = "%s"\n' "$id"
} | tee "$surname.txt"

Note that using the input given by the user potentially allows the user of the script to overwrite arbitrary files in the current directory (given that the permissions allows this).

| improve this answer | |
  • @kusalanda, how do i save the inputs to a file with the same name as the user? – Peter Thapelo Matlhasi Mar 10 at 9:41
  • @PeterThapeloMatlhasi See updated answer. – Kusalananda Mar 10 at 10:00
  • I learnt a lot from this, thank you! – FuRinKaZan_001 Mar 10 at 11:49

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.