stevo
stevo

Reputation: 181

Break out of if statement in while loop

Not sure if it's possible but I'm trying to break out of an if statement that's in a while loop. I do not want to exit the while loop though. I tried using exit and break but both exit the while loop.

The problem is that I don't know which folder the file I'm looking for is in, which is why I want to exit the current if statement when I match the searched file so that I can move on to the next serial number.

I have a text file called drives-fw-sn.txt that contains a list of serial numbers. Breakdown of code:

Here's a snippet of my code (there are more than three test folders). Note that it still contains the exit commands which exit the while loop.

while read node; do
   if find ./test1/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then
     echo "Log SN $node available"
     exit 1
   fi
   if find ./test2/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then
     echo "Log SN $node available"
     exit 1
   fi
   if find ./test3/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then
     echo "Log SN $node available"
     exit 1
   fi
done < drives-fw-sn.txt

Upvotes: 0

Views: 8953

Answers (3)

Yokai
Yokai

Reputation: 1220

This is actually pretty simple using the return built-in. Inside the while loop, set the if statement inside a small function block. When the if condition is met during the iterations, you can have it call the return where the script will return to the place where the function was called and continue from that point. I will show you with an example:

#!/bin/bash

read -p 'Input: ' HEY

func() { if true; then return; fi; }

while true; do

   echo "Input received!"
   func && break

done

In the func function, you have a very basic if statement that can hold any conditional value you want, such as your multiple conditions. When you include the return keyword, the if statement will then send the interpreter's "program counter", if you will, back to the point where the func function was called. Which in this case is inside the while loop. So it will be as if the function was not even called and as you can see, the next command in the while loop is a break keyword which will end the while loop. The function that contains the if-then-return code can be inside OR outside of your while loop as long as the conditions you place inside the if statement have been loaded into the interpreter first (bash reads scripts from top to bottom, similar to how C code is loaded).

There is also a lazy method and that is to wrap the entire script code inside a main function so you can use return at any point in your script, no matter if it is a loop or conditional statement. Here is an example of the above script modified in this manner:

#!/bin/bash

MAIN() {
read -p 'Input: ' HEY

while true; do

    if [ "$HEY" == "hello" ]; then
       return
    else
       echo "Incorrect input! Try again!"
       MAIN
    fi

done
}

MAIN

echo "Correct input received!"

Doing it in this manner as well will help keep variables local rather than creating global variables. To do this, at any point in the MAIN function you can define a variable as local so it only holds the value given to it while the MAIN function is running. Once the function is complete, the variables and their values are no more.

Hope this helps.

Upvotes: 2

Benjamin W.
Benjamin W.

Reputation: 52132

continue is the correct answer to your specific question how to "break out" of an if statement. Be aware that the if check is not actually checking if grep was successful, see the comment by chepner.

I would do this in a way that circumvents the problem in the first place:

Since you don't know which directory the file containing the serial number is going to be in, it doesn't matter in which order you're looking at them. Instead of listing all the directories separately and run find -exec on each of them, you can have grep just try all the log files directly:

while read -r node; do
    cat **/output_log | grep -m 1 "$node" && echo "Log SN $node available"
done < drives-fw-sn.txt

This requires the globstar shell option, shopt -s globstar, to enable the **/ construct. Depending on your directory structure, you might not even need it and could use something like test*/*log*/output_log instead.

cat is used to prevent grep from checking other files once it has found a match.

The output is a little different: the matches are prepended by the filename, but that can be adjusted with the corresponding grep options (-h to suppress filenames).

It also looks like you don't need regular expression matching; if so, you can use grep -F for fixed strings, which should be faster.

Lastly, depending on what the serial numbers look like, you might want to use the -w option (match only complete words) to avoid false positives due to substring matches.

Upvotes: 0

Greg Tarsa
Greg Tarsa

Reputation: 1642

There is no way to break out of the if, per se. But from the looks of your example, you could the continue command instead of exit to iterate the loop immediately.

Upvotes: 1

Related Questions