5r9n
5r9n

Reputation: 187

Make bash script exit if no user input in stdin

My bash script is supposed to get user input to deal with a particular file exiting as in:

if [ -e "formatted_log.csv" ]
then
    printf "\nPresence of formatted_log.csv file detected: It appears this script has already been run is this dir.\n"
    printf "Appending can cause errors.\n"
    read -e -p "Would you like to continue?[y/n]" stdin

This logic checks the user's input:

if [ $stdin = "n" ] || [ $stdin = "N" ];
then 
printf "\nOkay, exiting.\n"
exit;
fi
if [ $stdin != "y" ]&&[ $stdin != "Y" ]&&[ $stdin != "n" ]&&[ $stdin != "N" ]; 
then 
printf "\nPlease use a valid input (y/n)...exiting.\n"
exit;
    fi
fi

The issue is that if you just press enter the script executes as though a "y" or a "Y" have been input, and I don't know why. My understanding is that the way this is written, it should exit if the user puts in anything other than a y,Y,n,or N.

It prints this when you have no input:

master_script.sh: line 14: [: =: unary operator expected
master_script.sh: line 14: [: =: unary operator expected
master_script.sh: line 19: [: !=: unary operator expected

But doesn't exit – how can I make it exit?

Upvotes: 2

Views: 4201

Answers (2)

Inian
Inian

Reputation: 85885

The problem is NOT having the quotes around the variable $stdin which is not retained with an empty value when quotes are not present,

For example, the [...] sees the expressions as below when the variable is empty,

+ '[' = n ']'
script.sh: line 9: [: =: unary operator expected
+ '[' = N ']'
script.sh: line 9: [: =: unary operator expected
+ '[' '!=' y ']'
script.sh: line 14: [: !=: unary operator expected
+ '[' 0 eq 0 ']'

You need to properly quote them, to make it work, in line

9 if [ "$stdin" = "n" ] || [ "$stdin" = "N" ];

and

14  if [ "$stdin" != "y" ] && [ "$stdin" != "Y" ] && [ "$stdin" != "n" ] && [ "$stdin" != "N" ];

with this, the enter key press are safely handled as,

+ '[' '' = n ']'
+ '[' '' = N ']'
+ '[' '' '!=' y ']'
+ '[' '' '!=' Y ']'
+ '[' '' '!=' n ']'
+ '[' '' '!=' N ']'

with the above changes running the full script and pressing Enter on the prompt, in debugger mode,

 bash -x script.sh 
+ '[' -f file ']'
+ printf '\nPresence of formatted_log.csv file detected: It appears this script has already been run is this dir.\n'

Presence of formatted_log.csv file detected: It appears this script has already been run is this dir.
+ printf 'Appending can cause errors.\n'
Appending can cause errors.
+ read -e -p 'Would you like to continue?[y/n]' stdin
Would you like to continue?[y/n]
+ '[' '' = n ']'
+ '[' '' = N ']'
+ '[' '' '!=' y ']'
+ '[' '' '!=' Y ']'
+ '[' '' '!=' n ']'
+ '[' '' '!=' N ']'
+ printf '\nPlease use a valid input (y/n)...exiting.\n'

Please use a valid input (y/n)...exiting.
+ exit

As a healthy alternate you can just use the negative regex match on the list of allowed prompts as below

if [[ ! $stdin =~ ^(y|Y|n|N)$ ]]

Another efficient way to just check for just an empty string on the variable,

if [ "$stdin" = "" ]

Upvotes: 2

Benjamin W.
Benjamin W.

Reputation: 52506

Since you've tagged this with "Bash", you should have the more powerful [[ ]] operator at your disposal. You could then simplify to something like this:

read stdin

if [[ $stdin == [Nn] ]]; then
    echo "Exiting"
    exit
fi

if [[ $stdin != [YyNn] ]]; then
    echo "Invalid input, exiting"
    exit
fi

== (or =) and != in [[ ]] perform pattern matching, so you can use patterns to check if your input is valid, in a single expression like [YyNn].

If you want to ask for input until the user enters something valid, you could loop like this:

while [[ $stdin != [YyNn] ]]; do
    read -p 'Continue? ' stdin
done

Notice that while it's almost always good practice to quote your variables in Bash, you don't have to within [[ ]]. And if your pattern is in a variable, it actually must not be quoted, or it isn't interpreted as a pattern.

Upvotes: 4

Related Questions