Check if multiple 'If Statements failed - bash

I'm working on a script that checks (with If statements) if a variable contains a specific character. If a character is found the script executes some code. If a certain character cannot be found, the script will go into another If Statement to check if the variable contains another specific character, and so on.
this all works perfectly fine.
But I need the script to tell me if none of the characters are found, but i'm having some trouble accomplishing this goal. the script looks like this.
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
If all these If Statements cannot find their character I need the script to echo that these characters are not found.
I tried to put a If/else statement around all the other If statements, but this did not work for me.
if [[ ]]; then
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
if [[ "$results" == *"specific character"* ]]; then
do something.
fi
else
echo "characters are not found."
I can't seem to get it to work. Can somebody give me a push in the right direction?
Kind Regards,
Sleek

Use a case statement:
case "$results" in
*c*) do something;;
*d*) do something;;
*e*|*f*) do something
do another thing;;
*) echo "characters are not found.";;
esac

You could just set a variable in the if bodies and check whether it's set or not lateron, like so:
...
if [[ "$results" == *"specific character"* ]]; then
foundsmth=1
fi
if [[ -z ${foundsmth} ]] ; then
# nothing found
fi
Another solution would be to use regular expressions in combination with a switch-case construction as explained here.

For your if surrounding the individual if statements, you could use a regex:
if [[ $str =~ [abc] ]]; then
if [[ "$str" == *"a"* ]]; then
echo "a"
fi
if [[ "$str" == *"b"* ]]; then
echo "b"
fi
if [[ "$str" == *"c"* ]]; then
echo "c"
fi
else
echo "None of those characters are in str"
fi

I usually prefer a case like Dennis.
Since you already have it written as if's, you could use a compound if/elif/else, so long as it's ok to short-circuit out before checking them all.
if [[ "$results" == *"specific character"* ]]
then : do something.
elif [[ "$results" == *"specific character"* ]]
then : do something.
elif [[ "$results" == *"specific character"* ]]
then : do something.
else echo "characters are not found."
fi
On the other hand, if you need to check them ALL, whether or not any are found along the way, you're going to need mju's flag variable.
found=0;
if [[ "$results" == *"specific character"* ]]
then ((found++)); : do something.
fi
if [[ "$results" == *"specific character"* ]]
then ((found++)); : do something.
fi
if [[ "$results" == *"specific character"* ]]
then ((found++)); : do something.
fi
((found)) || echo "characters are not found."

Related

bash if statement with null value

my if condition with gt compare value and also if the value is null, but I want that gt compare null value, I just want that he compare only value
res=''
toto=5
if [[ "$toto" -gt "$res" ]]; then
...
else
...
fi
fi
solution is that, but not very good
if [[ ! -z "$res" ]]; then
if [[ "$toto" -gt "$res" ]]; then
...
else
...
fi
fi
Use &&.
if [[ ! -z "$res" && "$toto" -gt "$res" ]]
Other improvements you could make:
Replace ! -z with -n.
Remove unnecessary quotes.
Use ((...)) for numerical comparisons.
if [[ -n $res ]] && ((toto > res))
This Shellcheck-clean code handles empty $res in another way:
#! /bin/bash
res=''
toto=5
if [[ -z $res ]] ; then
: # $res is empty so don't compare with $toto
elif (( toto > res )); then
echo 'toto is greater than res'
else
echo 'toto is less than or equal to res'
fi
However, it's debatable whether it's better or worse than the "not very good" option suggested in the question. Deeper nesting is usually worse, but if-the-else chains are best avoided. The only advantage I would claim for the code in this answer is that it has a convenient place to put a helpful comment if one is useful.

Negating a regex test without an "if"

Ok, I think "bash" is short for "bash my head in."
Got this:
! [[ $var =~ ^[0-9]+$ ]] && echo "Supply integer values from the menu only. Nothing added." && return;
It' doesn't work. I have to do this:
if ! [[ $var =~ ^[0-9]+$ ]]; then
echo "Supply integer values from the menu only. Nothing added." && return
fi
Is there a way to get the first method to work?
UPDATE: Original code was edited. The above edited code works fine. Was a dumb mistake I made while thrashing around trying to figure out how to negate a regex. Closing this out.
The problem lies in the order of the operations / operation grouping. You can group operations in bash using curly braces; like this:
! [[ $var =~ ^[0-9]+$ ]] || { echo "Supply integer values from the menu only. Nothing added." && return; }
note that the ; is really necessary at the end of the code inside the curly braces.
The 2nd one is:
if ! [[ $var =~ ^[0-9]+$ ]]; then
echo "Supply integer values from the menu only. Nothing added." && return
fi
So the echo... executed when the regex doesn't match.
But in the first example, you use OR (|| in bash):
! [[ $var =~ ^[0-9]+$ ]] || echo "Supply integer values from the menu only. Nothing added." && return;
so the echo executed when the ! [[ ... ]] expression fails, that is the opposite what you wrote with the if. The same would be:
! [[ $var =~ ^[0-9]+$ ]] && echo "Supply integer values from the menu only. Nothing added." && return;
It's not obvious what "doesn't work" means, but your two statements aren't equivalent.
1195$ ! false || echo hello
1196$ ! true || echo hello
hello
1197$ if ! false; then echo hello ; fi
hello
1198$ if ! true; then echo hello ; fi
The roles of true and false are reversed between the two different usages.

bash: check if two variables both do or do not exist (aka comparing results of comparisons)

I am writing a bash script that sometimes will use environment variables GIT_DIR and GIT_WORK_TREE. The bash script can only operate correctly if either both variables exist or neither exist. In case there's a technical difference, it makes no difference
This works, but there has to be a better way:
if [[ -z "${GIT_DIR}" ]]; then
_GIT_DIR_EXISTS=0
else
_GIT_DIR_EXISTS=1
fi
if [[ -z "${GIT_WORK_TREE}" ]]; then
_GIT_WORK_TREE_EXISTS=0
else
_GIT_WORK_TREE_EXISTS=1
fi
if [[ "${_GIT_DIR_EXISTS}" -ne "${_GIT_WORK_TREE_EXISTS}" ]]; then
echo "GIT_DIR is ${GIT_DIR}"
echo "GIT_WORK_TREE is ${GIT_WORK_TREE}"
echo "Both or none must exist"
exit 1
fi
I tried:
if [[ (-z "${GIT_DIR}") -ne (-z "${GIT_WORK_TREE}") ]]; then
But that gives this error:
bash: syntax error in conditional expression
bash: syntax error near '-ne'
I then resorted to trying semi-random things, with varying errors:
if [[ -z "${GIT_DIR}" -ne -z "${GIT_WORK_TREE}" ]]; then
if [[ [-z "${GIT_DIR}"] -ne [-z "${GIT_WORK_TREE}"] ]]; then
if [[ [[-z "${GIT_DIR}"]] -ne [[-z "${GIT_WORK_TREE}"]] ]]; then
if [[ -z "${GIT_DIR}" ]] ^ [[ -z "${GIT_WORK_TREE}" ]]; then
if { [[ -z "${GIT_DIR}" ]] } -ne { [[ -z "${GIT_WORK_TREE}" ]] }; then
if [[ (( -z "${GIT_DIR}" )) -ne (( -z "${GIT_WORK_TREE}" )) ]]; then
I tried:
if [[ $(test -z "${GIT_DIR}") -ne $(test -z "${GIT_WORK_TREE}") ]]; then
But realized that doesn't work because it's a sub-process, and they'd need to be exported. as Socowl comments, this compares the outputs of the test commands which output nothing, not their exit statuses.
I apologize if this is a duplicate. I've searched here and google for a while, and must not be using the right terminology.
How about this:
if [[ "${GIT_DIR:+set}" != "${GIT_WORK_TREE:+set}" ]]; then
echo "GIT_DIR is '${GIT_DIR}'"
echo "GIT_WORK_TREE is '${GIT_WORK_TREE}'"
echo "Both or none must exist"
exit 1
fi
Explanation: ${var:+value} is a variant of parameter expansion that gives "value" if var is set to a nonempty string, or the empty string if var is unset or empty. So if both vars are unset/empty, it becomes if [[ "" != "" ]]; then, and if they're both set it becomes if [[ "set" != "set" ]]; then etc.
BTW, if you want to test whether the variables are set at all (even if to the empty string), use ${var+value} (note the lack of colon). The bash manual lists the :+ version, but not the + version.

IF condition in bash

I have just started learning to write bash scripts. This a simplified form of what I want to write.
The problem is despite of the input, it prints only "YES".
#! /usr/bin/bash
read input
if (("$input"== "y" || "$input" == "Y"))
then
echo "YES";
elif (("$input" == "n" || "$input" == "N"))
then
echo "NO";
else
echo "Not a valid input!!"
fi
Use [[ instead of (( like,
if [[ "$input" == "y" || "$input" == "Y" ]]
and also there must be a space exists before == operator.
ie,
input="n"
if [[ "$input" == "y" || "$input" == "Y" ]]
then
echo "YES";
elif [[ "$input" == "n" || "$input" == "N" ]]
then
echo "NO";
else
echo "Not a valid input!!"
fi
You could use regular expression also for condition checking purpose.
if [[ "$input" =~ ^[yY]$ ]]
then
echo "YES";
elif [[ "$input" =~ ^[nN]$ ]]
then
echo "NO";
else
echo "Not a valid input!!"
fi
When you automaticly convert the input to lowercase (using typeset), you do not have to bother with the the uppercases.
When you use an elif, always think 10 seconds for another solution. In this case you might want to use a "switch", in shell written as a case-statement:
#!/usr/bin/bash
typeset -l input
read input
case ${input} in
"y") echo "Yes";;
"n") echo "NO";;
*) echo "Not a valid input!!";;
esac

case or If string contains word1 and word2

In this example I want it to know if $# contains two words/symbols "load" and "/"
for one word/symbol this works
case "$#" in */*)
;;
echo "going to do stuff"
*)
echo "will do something else"
;;
esac
or
string='My string';
if [[ "$string" == *My* ]]
then
echo "It's there!";
fi
But if two words/symbols appear at random places I cant figure out how to do it.
Update:
The input will the module command. In this case I want to know if it is the module load with or without / that indicate version. the command will look like this
1) module load appname/1.1.1 or
2) module load appname
3) module (not load) (list, avail etc)
It is number 1 I am interested in for now.
3 will in some cases be variation of 1.
2 will be run as is but will include a message to the user
The slow way would be to iterate through the array twice and then check if both "load" and "/" were present, like this:
for element in $#; do [[ "$element" == "load" ]] && loadPresent=1; done
for element in $#; do [[ "$element" =~ ".*/.*" ]] && slashPresent=1; done
if [[ $loadPresent == 1 ]] && [[ $slashPresent == 1 ]]; then
echo "Contains load and /"
fi
(As I interpreted your question you want one parameter to be exactly "load" and another one to contain a slash.)
Something like this is possible:
if [[ ${#} =~ .*/.* && ${#} =~ ((^)|([ ]))load(($)|([ ])) ]]
then
echo both
fi
-or-
if LOAD=0 && SLASH=0 && \
for ARG in ${#};
do
if [ "${ARG#*/}" != "${ARG}" ]; then SLASH=1; fi
if [ "${ARG}" = "load" ]; then LOAD=1; fi
done && [ "${LOAD}${SLASH}" = "11" ];
then
echo both
fi
-or-
function loadslash()
{
LOAD=0 && SLASH=0
for ARG in ${#};
do
if [ "${ARG#*/}" != "${ARG}" ]; then SLASH=1; fi
if [ "${ARG}" = "load" ]; then LOAD=1; fi
done
test "${LOAD}${SLASH}" = "11"
}
if loadslash ${#}
then
echo both
fi
this will satisfy your requirements
if [[ $1 == "load" ]]; then
if [[ $2 == */* ]]; then
do first case
else
do second case
fi
else
do third case
fi

Resources