# Need help with BASH script Case Loop

This topic is 3676 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm having a problem and I can't find my error. It's driving me nuts!! Please help me, the details are as follows: I have a file named: sourcelist.tmp Its contents are a list of files I want to do stuff to, separated by spaces (no newlines). Below is an example of this file (The list is automatically generated so the directory trees look a little weird, but they're fine):
../Sources/Font/Test/../Letter.cpp ../Sources/Font/Test/../../Fileable/Fileable.cpp

And then I have a BASH script that processes these files. However, I'm having trouble with a case loop in it. Below is an excerpt of the trouble section:
# This variable indicates the files that have been processed so far
SOURCES="../Sources/Font/Test/LetterTest.cpp"
# This variable will be 1 until all files in sourcelist.tmp have been processed
LOOP=1
# This loop repeats until LOOP is null (once all files have been processed)
while [ ${LOOP} ]; do # Go through each file... for SOURCE in cat sourcelist.tmp; do # The following commented lines are not part of the script, but I use # them to test that the case loop is finding SOURCE when it is in SOURCES # and selecting that case, which it is not (my current problem): # SOURCES="$${SOURCES}|$${SOURCE}" # echo $${SOURCE}; # echo$${SOURCES}; case${SOURCE} in
# If the file is listed in SOURCES, then it has already been processed,
# so LOOP is set to null and we check the next file...  or end the while
# loop if this is the last file  (*** THIS NEVER HAPPENS!!!  WHY??? ***)
(${SOURCES}) LOOP="";; # File is not in SOURCES so we add it to SOURCES... (*) SOURCES="$${SOURCES}|$${SOURCE}" # and process it... if [ -e$${SOURCE} ]; then # I do my stuff to file and sourcelist.tmp here fi # Make sure LOOP is 1 as we must continue while loop LOOP=1 # Start new iteration of while loop (we want to start the for # loop over since sourelist.tmp may have changed) continue 2;; esac done done  If you help me you will be my official hero of the week! Thanks, Beau #### Share this post ##### Link to post ##### Share on other sites Advertisement Quote:  Original post by BeauMNI'm having a problem and I can't find my error. It's driving me nuts!! (1) Make sure there is a space before the ;; case terminator otherwise it may be missed by the parser. (2) lose the left paren in your pattern matches otherwise it's part of the match.  case$blah in    $SOURCES) echo "matched$SOURCES"      ;;    (*)      echo "a line beginning with a left parent has matched!"      ;;    *)      echo "default match"      ;;  esac

(3) I'm not completely sure you can use variable substitution in a case statement like that.

Use set -x to turn on debugging so you can see what's going on.

--smw

##### Share on other sites
I tried your suggestions but am still having the same problem. What happens is the wildcard case is selected everytime, the first case is always ignored (Even though I KNOW they match, assuming the variable substitution is working properly).

The debugging info was not detailed enough to help, it told nothing of what was happening inside the case statement, only the results. I'm going to try and see if there's a way to make it more verbose.

##### Share on other sites
Nope, the PATTERN in a case statement is evaluated when the case statement is evaluated. That means you can't change the PATTERN in subsequent iterations of your loop. You can't even stick it in a function and call that. You could, if you're feeling creative, stick it in a here document and eval it.

To tell you the truth, you're just better off using the tried-and-true way of processing lists from shell scripts. For example,

${SOURCE} will never be defined in the case statement because the case statement is evaluated before the for loop is run? But on the other hand, if you have an if statement inside the for loop, the if statement will get reevaluated on each iteration of that for loop? I've been searching through the BASH reference, but I haven't been able to find info on the order of evaluation in nested constructs such as these. How do we know precisely when something will be evaluated? Perhaps I just need a better understanding of how the shell goes about processing its scripts? Thanks again #### Share this post ##### Link to post ##### Share on other sites Quote:  Original post by BeauMN${SOURCE} will never be defined in the case statement because the case statement is evaluated before the for loop is run? But on the other hand, if you have an if statement inside the for loop, the if statement will get reevaluated on each iteration of that for loop?

After further investigation I figured out what the problem is.

As the bash documentation describes, variable substitution takes place when the case statement is evaluated. In other words, both ${SOURCE} and${SOURCES} are expanded as you expect.

Problem is, this is done at evaluation time, not at parse time. The parser will tokenize the match pattern into the various alternatives before the variable substitution takes place.

Consider a construct like this.
  matchme="a | b"  case a in     \$matchme)      echo "never gets here"      ;;    *)      echo "always gets here"      ;;  esac

There will be two patterns to match against: "a | b" and "*". Note the first pattern is not the same as "a" | "b" but instead consists of a 5-character token.

Unfortunately, try as I might, I seem unable to work around the dynamic construction of alternate cases. I stand by my previous assertion that you just need to come up with a simpler way of traversing your list.

--smw

##### Share on other sites
Ah, I get it now! Thanks for all your help!