I am trying to create a small script for creating simple, all-default Apache virtual host files (it should be used any time I establish a new web application).

This script prompts me for the domain.tld of the web application and also for its database credentials, in verified read operations:

read -p "Have you created db credentials already?" yn
case $yn in
    [Yy]* ) break;;
    [Nn]* ) exit;;
    * ) echo "Please create db credentials and then comeback;";;

read -p "Please enter the domain of your web application:" domain_1 && echo
read -p "Please enter the domain of your web application again:" domain_2 && echo
if [ "$domain_1" != "$domain_2" ]; then echo "Values unmatched. Please try again." && exit 2; fi

read -sp "Please enter the app DB root password:" dbrootp_1 && echo
read -sp "Please enter the app DB root password again:" dbrootp_2 && echo
if [ "$dbrootp_1" != "$dbrootp_2" ]; then echo "Values unmatched. Please try again." && exit 2; fi

read -sp "Please enter the app DB user password:" dbuserp_1 && echo
read -sp "Please enter the app DB user password again:" dbuserp_2 && echo
if [ "$dbuserp_1" != "$dbuserp_2" ]; then echo "Values unmatched. Please try again." && exit 2; fi

Why I do it with Bash

As for now I would prefer Bash automation over Ansible automation because Ansible has a steep learning curve and its docs (as well as some printed book I bought about it) where not clear or useful for me in learning how to use it). I also prefer not to use Docker images and then change them after-build.

My problem

The entire Bash script (which I haven't brought here in its fullness) is a bit longer and the above "heavy" chuck of text makes it significantly longer - yet it is mostly a cosmetic issue.

My question

Is there an alternative for the verified read operations? A utility that both prompts twice and compares in one go?

Related: The need for $1 and $2 for comparison with an here-string


2 Answers 2


How about a shell function? Like

function read_n_verify  {
    read -p "$2: " TMP1
    read -p "$2 again: " TMP2
    [ "$TMP1" != "$TMP2" ] &&
    { echo "Values unmatched. Please try again."; return 2; }
    read "$1" <<< "$TMP1"
read_n_verify domain "Please enter the domain of your web application" 
read_n_verify dbrootp "Please enter the app DB root password" 
read_n_verify dbuserp "Please enter the app DB user password"

Then do your desired action/s with $domain, $dbrootp, $dbuserp.

$1 is used to transport the variable name for the later read from the "here string", which in turn is used as it's easier here than a (could be used as well) "here document".

$2 contains the prompt (free) text, used last to allow for (sort of) "unlimited" text length.

Upper case TMP and [ ... ] && "sugar-syntax" (whatever this might be) are used by personal preference.

if - then - fi could be used as well and would eliminate the need for the braces that collect several commands into one single command to be executed as the && branch.

  • Passwords with trailing spaces and backslashes may be improperly read here.
    – Kusalananda
    Nov 25, 2018 at 8:55
  • I think I miss just one more thing, if we read TMP1 and TMP2, into $2 how come there isn't a "clash" here and both still exist to be later checked by the if-then?
    – user149572
    Jan 1, 2019 at 9:13
  • @Kusalananda this is a good point, thank you for pointing it out.
    – user149572
    Jan 1, 2019 at 9:14
  • @JohnDoea Nothing is read into $2. The thing in $2 is used as part of the prompt. The variable whose name is in $1 is given the value of $TMP1 in the last read (which would be better written printf -v "$1" '%s' "$TMP1"). Also note that the positional parameters are local to the function and separate from the positional parameters in the main script. There is no clash between them.
    – Kusalananda
    Jan 1, 2019 at 10:23
  • @Kusalananda:  Values with leading whitespace will have the whitespace stripped off, also. Jun 22, 2019 at 19:18

I would do it like this:

while [[ $string != 'string' ]] || [[ $string == '' ]] 
    read -p "Please enter the domain of your web application: " string
    echo "Please enter the domain of your web application: "
Command 1
Command 2

Less typing.

Of course you would need a section like this for all of your questions.

Other than the way you have it and the way I have it, not really any more options.

  • Hi Michael. Why is there an echo after the read -p? Also, would you use while for command 1 and 2 and 3? I misunderstand the code.
    – user149572
    Dec 17, 2018 at 22:25
  • It outputs the string prompting the user without the newline before reading. @JohnDoea Those two commands would be the commands your passing the var's too, so no while loop. Dec 18, 2018 at 1:21
  • It is verifying that you typed it correctly. Comparing the read string with the response to the echo. If they don't mach the while loop continues till they do match. Once they match the next commands execute. And the variable string is retained to be used in the latter commands. Dec 18, 2018 at 1:36
  • (1) You seem to have missed the point of the OP’s follow-up question.  Your code issues the prompt twice for every time it reads a value.  (2) I don’t understand how this is supposed to work — and, in fact, I cannot get it to work.  I tried it, and I can type an arbitrary value (e.g., foo) any number of times, and it just keeps looping — until I type string as an input — and then, I only need to type that once.  (How do you expect to read two values and compare them if you don’t have two variables?) … (Cont’d) Jun 22, 2019 at 19:18
  • (Cont’d) …  (3) As far as I can tell, the [[ $string == '' ]] part of your code seems to be inert — [[ $string != 'string' ]] || [[ $string == '' ]] seems to be completely equivalent to [[ $string != 'string' ]]. Jun 22, 2019 at 19:19

You must log in to answer this question.