4

So I have a project in my cyber security class to make a bash game. I like to make one of those medieval games where you make farms and mines to get resources. Well I like to make something like that. To do that I have to have two while loops running. Like this

while [ blah ]; do

    blah

done

while [ blah ]; do

    blah    

done

Is it possible to run two while loops at the same time and if I am writing it wrong how do I write it?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Lifetake
  • 191
  • 4
  • 11
  • 2
    How does "Yes, No, Maybe" grab you for an answer? A lot depends on what you're planning for those two loops to do, and how they will communicate with each other. You can nest loops, but that's probably not what you're after. You can run two processes in background that are able to run concurrently; you have to know how they'll communicate with each other, and the top process needs to do something (or almost nothing, just hang around) while they're running. The IPC for the two processes will be your main problem; how do they communicate? – Jonathan Leffler Dec 02 '12 at 00:33

4 Answers4

9

If you put a & after each done, like done&, you will create new processes in the background that run the while loops. You will have to be careful to realize what this means though, since the bash script will continue executing commands after creating those new processes even if they are not finished. You might use the wait command to prevent this from happening, but I'm not too used to using that so I cannot vouch for it.

Victor Zamanian
  • 3,100
  • 24
  • 31
  • thank you i'll start testing it out to see how it work. And do you know any info an how I use wait. – Lifetake Dec 02 '12 at 00:52
  • 2
    Using `wait` is trivial; you write `wait` in your script as a command on its own. The script doesn't move on to the next command (after the `wait`) until all the child processes started by the script have completed. – Jonathan Leffler Dec 02 '12 at 00:56
  • Hey also would it look like this. – Lifetake Dec 02 '12 at 00:57
  • while [ blah == blah5 ]; do done& while [ blah == blah6 ]; do done – Lifetake Dec 02 '12 at 01:06
  • @JonathanLeffler Thanks for that input! @Lifetake Yes that's what I had in mind. Since you don't put a `&` after the `done` of the second loop, the script won't move on until the second loop is finished. But still you would need a `wait` in order to let the first loop finish before moving on if that is what you need. – Victor Zamanian Dec 02 '12 at 01:13
  • well what I want it to do is one while loop will act as a decision maker for you to build like a mine or a farm. Then the second while will act as a resource maker by constantly making resources depending on how many buildings you have. I can write all the making and constant resources, but I do not now how to the done & would be – Lifetake Dec 02 '12 at 01:23
  • 2
    It will be just like you proposed in the comment you made earlier. `while condition; do COMMANDS; done & while other_condition; do OTHER_COMMANDS; done & wait`, basically. The most important part here *concurrency*, and all that that entails. That would probably be an important part for you to focus on should you go with this route. Otherwise I'd suggest you make a large main program loop that just goes through the different things that need to be done each step in the game loop, rather than have several loops running *at the same time*. – Victor Zamanian Dec 02 '12 at 01:29
  • my question is why I might use wait if the second while is for the currency which must continue to run at all times – Lifetake Dec 02 '12 at 01:32
  • 1
    It depends on your script. If you have further commands after the `while` loops that you *don't* want to run until the loops are finished, then you need to use `wait`. If you don't have further commands that should not run unless the loops are finished, then you don't need `wait`. – Victor Zamanian Dec 02 '12 at 01:38
  • its helpful if you put them in a function too, but either way you can wait on a single process by storing its job id after you fork it with & lastprocessjid=41 – technosaurus Dec 02 '12 at 01:52
  • @Lifetake: I might suggest that you use `wait` even if you don't need it. That way, if you've accidentally created an infinite loop, you will notice that because your script will not finish. If you *don't* use `wait`, your script will finish and give your shell prompt back, but there will be an invisible process still running in the background that you would in that case have to manually kill. So for testing/debugging purposes, `wait` could be a good idea. You can remove it later if you desperately don't want it in your finished script. It doesn't really hurt to have it there though. :-) – Victor Zamanian Dec 02 '12 at 01:58
  • well though my script is to be a infinite script actually because of the layout of the game – Lifetake Dec 02 '12 at 17:25
1

Yes, but you will have to fork a new process for each while loop to be executing in. Technically, they won't both run at the same time (unless you consider multiple cores, but this isn't even garaunteed).

Below is a link to how to fork multiple processes using bash.

Forking / Multi-Threaded Processes | Bash

Since you mention this is a school project, I'll stop here lest I help you "not learn".

R

Community
  • 1
  • 1
Ross
  • 1,639
  • 1
  • 18
  • 22
  • I don't quite understand what this forking thing is, I don't understand what happening by using it. – Lifetake Dec 02 '12 at 00:56
  • 1
    On Unix, `fork()` is the system call used to create every new process except the very first. Your shell uses `fork()` every time it runs a new command (except when you invoke the new command with `exec`). It uses `fork()` when you run a shell script in the background with the `&`; after the `fork()`, the child process gets on with the background work while the parent shell gets on with its next job. The `fork()` system call gives you two almost identical copies of the original process; the main difference is that the child's process ID (PID) is different, and it knows that it is the child. – Jonathan Leffler Dec 02 '12 at 00:59
  • 1
    And I'd imagine you would get some kudos from implementing fork in the project as it probably wasn't assumed or suggested and therefore would seem a bit ingenious (or look like you asked online, heh) – Ross Dec 02 '12 at 01:14
1

First things first, wrap the loop into a function and then fork it. This is done when you want to split a process, for example, if I'm processing a CSV with 160,000+ lines, single process/"thread" will take hours. If you wrap the loop into a function and simply fork it, you will have x amount of processes running, then add wait/kill defunct process loop and you are done. here what you are looking at.

while loop with nested loop:

   function jobA() { 
       while read STR;
        do
            touch $1_temp
               key=$(IFS="|";set -- $STR; echo $1)                  
                for each in ${blah[@]};
                    do
                        #echo "$each"

                    done

        done <$1;
    }


  for i in ${blah[@]};  
            do 
            echo "$i"

            $(jobRDtemp $i) &

            child_pid=$!
            parent_pid=$$
            PIDS+=($child_pid)

            echo "forked process $child_pid with parent $parent_pid"
        done

            for pid in ${PIDS[@]};
                do
                    wait $pid
                done
                    echo "all jobs done"
                    sleep 1

Now this is wrapped, here is example of a FORKED loop. this means you will have parallel processes run in the background, WAIT will wait for ALL to complete before proceeding. This is important for some type of scripts.

Also, DO NOT use nested FOR loops written C style like presented above, example:

for (( i = 1; i <= 5; i++ ))      ### Outer for loop ###

This is VERY slow. use THIS type:

for each in ${blah[@]};
                    do
                        #echo "$each"
                            if [ "$key" = "$each" ]; then
                                # echo  "less than $keyValNeed..."
                                echo $STR >> $1_temp
                            fi 
                    done
Moses Davidowitz
  • 982
  • 11
  • 28
0

You could also use nested for loops

for (( i = 1; i <= 5; i++ ))      ### Outer for loop ###
do

    for (( j = 1 ; j <= 5; j++ )) ### Inner for loop ###
    do
         echo -n "$i "
    done

    echo "" #### print the new line ###

done

EDIT: I thought you meant Nested Loop but reading again you said running both loops "at the same time". I will leave my answer here though.

gibertoni
  • 1,368
  • 12
  • 21