Bash script, syntax on OR statement - bash

Can someone tell me why this script isnt working? I'm getting
./FileDirTest.sh: line 10: [: missing `]'
./FileDirTest.sh: line 10: n: command not found
./FileDirTest.sh: line 13: [: missing `]'
./FileDirTest.sh: line 13: n: command not found
Here is my script.
if [ -d "$PASSED1" ]
then echo "Do you want to execute whole directory?(Y/N)"
read answer
if [ "$answer" == "y" || "$answer" == "Y" ] ;
then echo "Execute"
fi
if [ "$answer" == "n" || "$answer" == "N" ] ;
then echo "No"
exit 1
fi
fi
Im sure it is something simple. I new to all of this.

|| is not a valid operator for the [ command; you can only use it to join two distinct [ commands:
if [ "$answer" = "y" ] || [ "$answer" = "Y" ];
You can, however, use || inside bash's conditional command:
if [[ "$answer" = "y" || "$answer" = "Y" ]];
The first of the two errors occurs because ||, being a special shell operator, indicates that the previous command is complete, but [ requires ] be given as the final argument. The second error occurs because the value of $answer, immediately following ||, is taken as the name of the command to run.

In addition to #Chepner's answer, you can also use, bash -o operator,
if [ "$answer" == "y" -o "$answer" == "Y" ]; then
echo "Execute"
else
echo "No"
exit 1
fi

Related

Yes/No shell script causing "==Yes" loop?

I'm creating a shell script to automatically do sudo apt update/upgrade/autoremove/autoclean (first bash script of my life), everything works but the yes or no section
Here's my code:
#!/bin/bash
echo "Updating and upgrading system components"
sudo apt update
sudo apt upgrade
echo "Starting cleaning and removing unnecessary files"
sudo apt autoremove
sudo apt autoclean
echo "Do you want to check if a new distribution update is available? Y/N"
read -p "Check system distribution updates?" answer
if ["$answer" == "Y" || "$answer" == "Yes" || "$answer" == "y" || "$answer" == "yes"]
then
sudo do-release-upgrade
else
exit
fi
After answering one of these option shell starts printing in loop "==Yes"
Any idea?
[ needs to be separated by space from its arguments. ["$answer" gets parsed as a single command with two arguments, == and Y. Such a command doesn't exist, so it fails, and || tries the next command. The next command is yes: it's a command that prints its arguments infinitely. The arguments in this case are == and Yes.
The correct way to write the condition is
if [ "$answer" == "Y" ] || [ "$answer" == "Yes" ] || [ "$answer" == "y" ] || [ "$answer" == "yes" ]
or
if [ "$answer" == "Y" -o "$answer" == "Yes" -o "$answer" == "y" -o "$answer" == "yes" ]
or, if you're using bash
if [[ $answer == Y || $answer == Yes || $answer == y || $answer == yes ]]
You can also use parameter expansion to lowercase the answer (but it includes yEs etc. among the accepted answers)
if [[ ${answer,} == y || ${answer,,} == yes ]]
Or you can use a regex with the =~ operator
if [[ ${answer,,} =~ ^y(es)?$ ]]
Under shopt -s extglob, you can use a pattern to match both the cases in one expression:
if [[ ${answer,,} == y?(es) ]]

Unexpected operator in if statement

In the following two lines I get this error?
What is wrong?
Debian Buster
my.sh: 101: [: !=: unexpected operator
my.sh: 103: [: !=: unexpected operator
if [ $CONTINUE != "y" ] && [ "$CONTINUE" != "n" ]; then
elif [ $CONTINUE = "n" ]; then
update
echo "\nContinue downloading? [y/n]"
read CONTINUE
# Error: Invalid argument
if [ $CONTINUE != "y" ] && [ $CONTINUE != "n" ]; then
error "Invalid argument"
elif [ $CONTINUE = "n" ]; then
echo "\nDonwload terminated!"
exit
fi
The script you’ve posted has various issues, which are highlighted by ShellCheck:
Line 1:
echo "\nContinue downloading? [y/n]"
^-- SC2028: echo may not expand escape sequences. Use printf.
Line 2:
read CONTINUE
^-- SC2162: read without -r will mangle backslashes.
Line 5:
if [ $CONTINUE != "y" ] && [ $CONTINUE != "n" ]; then
^-- SC2086: Double quote to prevent globbing and word splitting.
^-- SC2086: Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
if [ "$CONTINUE" != "y" ] && [ "$CONTINUE" != "n" ]; then
Line 7:
elif [ $CONTINUE = "n" ]; then
^-- SC2086: Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
elif [ "$CONTINUE" = "n" ]; then
Line 8:
echo "\nDonwload terminated!"
^-- SC2028: echo may not expand escape sequences. Use printf.
But despite these issues the script actually otherwise works as expected on Debian (Buster)’s default shell (which is dash). You might be running a non-default shell. The easiest way to solve your issue is therefore to
Declare a valid shebang line
Fix the issues highlighted above.
Which leaves us with this:
#!/bin/sh
printf "\nContinue downloading? [y/n] "
read -r CONTINUE
error() {
printf >&2 '%s\n' "$#"
exit 1
}
if [ "$CONTINUE" != y ] && [ "$CONTINUE" != n ]; then
error "Invalid argument"
elif [ "$CONTINUE" = n ]; then
printf "\nDownload terminated!\n"
exit
fi
(This also adds a definition for the undefined error call; substitute as appropriate.)

Is there a better solution to this if statement problem?

Bash function to execute a git pull in all subfolder where a .git directory is found.
I'm having issues with the last elif.
This part:
...
elif [ $answer == '' || $answer -ne 'y' || $answer -ne 'n' ] ; then
echo '---Please answer with y/n---'
...
Whole code of the function:
dogitpull () {
for i in */.git; do ( echo $i; cd $i/..; ); done
echo -n 'Are you sure? (y/n) '
read answer
echo $answer
if [ $answer == 'n' ] ; then
echo '---CANCELED---'
elif [ $answer == 'y' ] ; then
echo '---------------------------'
for d in */.git; do ( echo $d; cd $d/..; git pull; echo '---------------------------'; ); done
elif [ $answer == '' || $answer -ne 'y' || $answer -ne 'n' ] ; then
echo '---Please answer with y/n---'
fi
}
If the answer is empty (pressed enter), is not 'y' or is not 'n' there should be the text "Please answer with y or n" and should start again from the "read answer".
Does anybody have a solution to this?
Output: when pressing enter
-bash: [: ==: unary operator expected
-bash: [: ==: unary operator expected
-bash: [: missing `]'
-bash: -ne: command not found
-bash: -ne: command not found
Output: when entering something else than y or n
-bash: [: missing `]'
-bash: a: command not found
-bash: a: command not found
use case. example:
#!/bin/bash
echo -n 'Are you sure? (y/n) '
read answer
echo $answer
case "$answer" in
n|N) echo '---CANCELED---';;
y|Y) echo '-- yes ---';;
*) echo '---Please answer with y/n---';;
esac
The problem here is that you didn't quote the variable. When $answer is empty then [ $answer == '' ] expands to [ == '' ] which gives an error since there is nothing on the left hand side of the ==.
Fix
Quote your your variable and then proceed to fix the following errors (courtesy of Kamil Cuk):
-ne is for numbers, it will error with "Integer expression expected". Use != instead.
|| is not valid for [. Use -o or put the || outside the braces: [ ... ] || [ ... ] || [ .. ]
elif [ "$answer" = '' ] || [ "$answer" != 'y' ] || [ "$answer" != 'n' ]
Improvements
Use a single = instead of ==. [ a = b] is the official and portable way to check equality of a and b.
Instead of elif [ "$answer" == '' || "$answer" -ne 'y' || "$answer" -ne 'n' you may want to write just else which has the samme effect due to the preceding if-cases.
if [ "$answer" = 'n' ] ; then
# ...
elif [ "$answer" = 'y' ] ; then
# ...
else
# ...
fi
If answer is not a y and it is not an n, then you need to take action.
elif [ "$answer" != 'y' ] && [ "$answer" != 'n' ]; then
echo '---Please answer with y/n---'
Or you can do Moore's law and:
If not both: answer is 'Y' or answer is 'n', then you need to take action.
elif ! { [ "$answer" = 'y' ] || [ "$answer" = 'n' ]; }; then
echo '---Please answer with y/n---'
or with a ( subshell:
elif ! ( [ "$answer" = 'y' ] || [ "$answer" = 'n' ] ); then
echo '---Please answer with y/n---'

Bash if... then... syntax error

I am trying to remove something based on user input using bash/sh, here is my code :
echo "remove ? [Y/n]"
read REMOVE
if [ $REMOVE != "n" ] || [ $REMOVE !="N" ];then
# ... do something ...
echo "done"
fi
the error I am getting is something like:
./run.sh: line 8: syntax error near unexpected symbol « then »
./run.sh: line 8: `if [ $REMOVE != "n" ] || [ $REMOVE !="N" ];then'
I tried to add/remove spaces many times, and I still don't understand what happens. I also don't really understand all the differences between [[ statement ]] [statement] or ((statement)).
If someone can help...
In your original problem, you need a space here
$REMOVE != "N"
In your comment response to shruti1810, it sounds like your $REMOVE variable doesn't contain what you think it contains.
Try adding
echo $REMOVE
to your script.
I typically use this construct
if [ "x$REMOVE" != "xn" ] || [ "x$REMOVE" != "xN" ]
then
# ... do something ...
echo "done"
fi
to ensure that my arguments are both valid.
Please try this:
echo "remove ? [Y/n]"
read REMOVE
if [ $REMOVE != "n" ] && [ $REMOVE != "N" ]
then
# ... do something ...
echo "done"
fi
Quote the "$REMOVE" and insert space around the "!=" -- like this;
if [ "$REMOVE" != "n" ] || [ "$REMOVE" != "N" ];then
# ... do something ...
echo "done"
fi
The problem is that is REMOVE is not set or if it is set to an empty string (like if you just press return on the 'read') you will get $REMOVE substituted to nothing and your expression would look like [ != "N" ] which will produce an unary operator expected error.

Too many arguments error in bash

I am writing a script to delete all files in a directory for practice. I am using quotes around my variables, and yet I am still getting the following error:
/usr/local/bin/deleteall: line 6: [: too many arguments
/usr/local/bin/deleteall: line 11: [: too many arguments
Here is my code:
#!/bin/bash
#Deletes all files in the current directory
read -p "You are about to delete all files in $(pwd). Are you sure you want to do this? y/n" yn
echo $yn
if [ [ "$yn" = "y" ] -o [ "$yn" = "Y" ] ] ; then
for i in `ls`; do
rm $i
done
exit;
elif [ [ "$yn" = "n" ] -o [ "$yn" = "N" ] ] ; then
exit;
else
read -p "Please enter y (yes) or n (no)"
exit;
fi
And this is the entire output:
You are about to delete all files in <my dir>. Are you sure you want to do this? y/nn
n
/usr/local/bin/deleteall: line 6: [: too many arguments
/usr/local/bin/deleteall: line 11: [: too many arguments
Please enter y (yes) or n (no)n
What am I doing wrong?
This line appears to be problem:
if [ [ "$yn" = "y" ] -o [ "$yn" = "Y" ] ] ; then
You can replace this with:
if [[ "$yn" == [yY] ]]; then
PS: Do same for the line where you check n or N.
You can't nest []. It's literally interpreting the nested brackets as arguments, and printing an error that you have too many.
Just this will work
if [ "$yn" = "y" -o "$yn" = "Y" ]; then
Another alternate syntax using double brackets and same logic
if [[ $yn == "y" || $yn == "Y" ]]; then
Also
for i in `ls`; do
rm $i
done
Should really be
for i in *; do
[ -f "$i" ] && rm $i
done
So it only tries to remove regular files (you will get errors for dirs, unless you overwrote rm, and you can decide what you want to do with symlinks). And ls is simply extraneous.
this is what you want:
read -p "Are you sure? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
for i in `ls`; do
rm -rf $i
done
fi
if [[ $REPLY =~ ^[Nn]$ ]]
then
#do what you want
done
fi

Resources