While loop in OR condition not working. BASH shell - bash

I am trying to run a shell script in OS X Terminal. The program terminates whenever you enter an m or a.
Problem is, I can't get the OR statement working.
#!/bin/sh
read File
while [ "$File" != "m" ] || [ "$File" != "a" ]
do
read File
done
When I just do
while [ "$File" != "m" ]
It works perfectly fine. I have tried multiple methods, such as
while test $File != "m" || test $File != "a"
while test $File != "m" -o test $File != "a"
while [ $File != "m" -o $File != "a" ]
None of them seem to work.
The above code I posted does not stop looping when the user inputs an "m" or an

I suggest to replace
while [ "$File" != "m" ] || [ "$File" != "a" ]
by
while [ "$File" != "m" ] && [ "$File" != "a" ]
or
until [ "$File" = "m" ] || [ "$File" = "a" ]
or with a regex (bash):
while [[ ! $File =~ m|a ]]
See from bash: help until

Related

bash if-statement check for file

I know how to check for a file in bash using this code
file=$1
if [ -f "$file" ]
then
...
fi
But I want to do something when it's not a file.
file=$3
if [ "$1" == "" ] || [ "$2" == "" ] || [ $file is not a file??? ]
then
echo "use: notEmpty notEmpty file"
fi
Can anyone help me out?
if [ "$1" == "" ] || [ "$2" == "" ] || [ ! -f "$file" ]
The whitespaces after [ and before ] are important.

[: too many arguments with Binary Conditional Operators

I am trying to write a script but it is giving the above error
if [ [ [ "$1" != "abc" ] && [ "$1" != "def" ] ] || [ [ "$2" != "1" ] && [ "$2" != "0" ] ] ];
then
echo "Hello World"
fi
Be careful with && and ||. You can simplify it to this in BASH:
if [[ "$1" != "abc" && "$1" != "def" ]] || [[ "$2" != "1" && "$2" != "0" ]];
then
echo "Hello World"
fi

How can I use a condition 'and' condition in a script?

I'm trying to check if both conditions return the expected values.
I want to be sure that both return the expected value before continuing...
My problematic line is: if [ [ $ansmob = "y" ] || [ $flagbook != "1" ] ];
read -r -p "Would you like to add $site.booking.local as well? [y/n] " ansbook
if [ $ansbook = "y" ];
then sed "s/ServerAlias.*/& $site.booking.local/" -i $workdir/$site$dom.conf
flagbook="1"
fi
read -r -p "Would you like to add m.$site.booking.local? [y/n] " ansmob
if [ [ $ansmob = "y" ] || [ $flagbook != "1" ] ];
then sed "s/& $site.booking.local/& $site.booking.local m.$site.booking.local/" -i $workdir/$site$dom.conf
else
sed "s/ServerAlias.* /& m.$site.booking.local/" -i $workdir/$site$dom.conf
flagmobile="1"
fi
Replace
if [ [ $ansmob = "y" ] || [ $flagbook != "1" ] ];
with
if [ "$ansmob" = "y" ] || [ "$flagbook" != "1" ]
with bash's double brackets, you can use && and ||
if [[ $ansmob = "y" || $flagbook -ne 1 ]]
Within double brackets, it's not strictly necessary to quote the variables: this command is smart about evaluating expressions with empty variables.
The binary && operator is the syntax for the AND operation.

Bash IF : multiple conditions

I've been trying to make this thing work for a couple of hours but I can't get it to work :
if [ "$P" = "SFTP" -a "$PORT" != "22" ] || [ "$P" = "FTPS" && [ "$PORT" != "990" -a "$PORT" != "21" ] ] ; then
Can someone help me ? I know that multiple conditions can be written like this :
if [ "$P" = "SFTP" ] && [ "$PORT" != "22" ]; then
but how can I imbricate theses conditions like in my first example?
You can't nest expressions in single brackets. It should be written like this:
if [ "$P" = "SFTP" -a "$PORT" != "22" ] || [ "$P" = "FTPS" -a "$PORT" != "990" -a "$PORT" != "21" ] ; then
This can be written as a single expressions as:
if [ \( "$P" = "SFTP" -a "$PORT" != "22" \) -o \( "$P" = "FTPS" -a "$PORT" != "990" -a "$PORT" != "21" \) ] ; then
although is is not fully compatible with all shells.
Since you are using bash, you can use double brackets to make the command more readable:
if [[ ( $P = "SFTP" && $PORT != "22" ) || ( $P = "FTPS" && $PORT != "990" && $PORT != "21" ) ]] ; then

Boolean Expressions in Shell Scripts

What's the "right" way to do the following as a boolean expression?
for i in `ls $1/resources`; do
if [ $i != "database.db" ]
then
if [ $i != "tiles" ]
then
if [ $i != "map.pdf" ]
then
if [ $i != "map.png" ]
then
svn export -q $1/resources/$i ../MyProject/Resources/$i
...
The other solutions have a couple of common mistakes:
http://www.pixelbeat.org/programming/shell_script_mistakes.html
for i in $(ls ...) is redundant/problematic
just do: for i in $1/resources*; do ...
[ $i != file1 -a $1 != file2 ] This actually has 2 problems.
a. The $i is not quoted, hence names with spaces will cause issues
b. -a is inefficient if stating files as it doesn't short circuit (I know the above is not stating files).
So instead try:
for i in $1/resources/*; do
if [ "$i" != "database.db" ] &&
[ "$i" != "tiles" ] &&
[ "$i" != "map.pdf" ] &&
[ "$i" != "map.png" ]; then
svn export -q "$i" "../MyProject/Resources/$(basename $i)"
fi
done
Even shorter:
for i in `ls $1/resources`; do
if [ $i != databse.db -a $i != titles -a $i != map.pdf ]; then
svn export -q $1/resources/$i ../MyProject/Resources/$i
fi
done;
The -a in the if expression is the equivalent of the boolean AND in shell-tests. For more see man test
Consider using a case statement:
for i in $(ls $1/resources); do
case $i in
database.db|tiles|map.pdf|map.png)
;;
*)
svn export -q $1/resources/$i ../MyProject/Resources/$i;;
esac
done
for i in `ls $1/resources`; do
if [ $i != "database.db" ] && [ $i != "tiles" ] && [ $i != "map.pdf" ] && [ $i != "map.png" ]; then
svn export -q $1/resources/$i ../MyProject/Resources/$i
For future reference, the new [[ test operator is preferred. The accepted answer is close and everything mentioned applies, but that answer will require lots of quoting and calls to multiple tests.
The preferred method would be something like:
for i in $1/resources/*; do
if [[ $i != "database.db" && $i != "tiles" &&
$i != "map.pdf" && $i != "map.png" ]]; then
svn export -q "$i" "../MyProject/Resources/$(basename $i)"
fi
done

Resources