Unable to set Global variable outside while loop

Below is my code:

 
count=0
if 
...
...
else
...
find * -prune -type d | sort -r -n |  while read d; do
count=1
 if [ "$count" == "1" ]; then
 echo "Count1:$count"
 ...
 ...
 break 2;
 fi
...
done 
...
fi
echo "Count2:$count"
if [ "$count" != "1" ]; then
echo "Problem"
fi

Output:
Count1:1
Count2:0
Problem

I did not expect "Problem" to be printed as i was expecting Count2:1.
I tried putting "( while read d; do" but i am not sure where should i close ")" to get it working.
Where am i going wrong and how should i resolve this.

Deja-vu: Question around Global Variable

  1. count is not changed anywhere (visible)
  2. You parse entries d , but dont use them.
  3. HERE, Problem is printed because $count NOT equals 1 (as it still is set to 0 and 0!=1, so it is printed).

Same question as in your other thread, what do you want to achieve?

  1. count is changed and set to 1 just below the find statement and I wish that value to be taken over to the last if condition.

  2. -d is used but its not relavent to the problem so i did not share the entire code. Let me know if you need that to debug the issue.

  3. My expectation / need is $count SHOULD equals 1

The count=1 in your code is set in the while loop is in the last command in a pipeline. In the shell you're using the last command in a pipeline is run in a subshell. Variables set in a subshell are not available when you get back to the parent shell. So, everything in your script from where count is updated to where you use that updated value need to be in the same subshell. So...:

count=0
if 
...
...
else
...
find * -prune -type d | sort -r -n | ( while read d
    do
     count=1
     if [ "$count" == "1" ]; then
     echo "Count1:$count"
     ...
     ...
     break 2;
     fi
     ...
    done 
    ...
    fi
    echo "Count2:$count"
    if [ "$count" != "1" ]; then
    echo "Problem"
    fi
)

Note that break 2 breaks out of two enclosing loops and there is only one enclosing loop in this code. If you are trying to break out of a loop that contains the pipeline you've shown us, it won't work because you can't break out of a loop in a parent environment, only out of loops in the current (subshell) shell execution environment.

1 Like

I tried the '()' suggestion you gave however, i get this error and the script wont run.

script.sh: line 69: syntax error near unexpected token `fi'
script.sh: line 69: `fi '

Even if i remove the break statement i see the above error while running the script.

Also, I need to break from the If statement as well as the while loop, hence I needed break 2 .

Can you help me fix this ?

The break n command breaks out of n enclosing for , until , or while loops. The number of if statements present inside those loops do not matter (no matter how deeply nested in if statements the break is).

I can't help you fix a syntax error on line 69 of a script when I have seen less than twenty lines of your script and large portions of that are:

...

Obviously, the closing parenthesis I added has to go after the done that ends your while loop. It may need to be several lines after the done if you use $count outside the while loop.

In that case let me just post my case and what i m trying to do.

I m in a directory that has a few sub directories.

I need to grep for a string in all files in all sub directories starting with the sub directory with the latest time stamp.

If grep string is found i need to break off and stop the search [this is why i was using break ].

If the desired string is not found I need to grep for the string in the other sub directories.

After the process completes I should display the results of the grep if the desired search string has been found in any of the files or else Display a message that "No records Found"

I hope you can give me an idea as my expertise did not help.

This leaves a few details to be explained: you effectively search for the first match in each subdirectory, yes? Or do you want to stop the search completely after the first found match?

Supposing it is the first, here is a sketch. Because your inoput was sketchy at best the script is, too. You will have to fill in some parts. Note that the search pattern might not work if it contains too much regexp. In this case you will have to report back:

typeset -i lFound=0
typeset    fDir=""
typeset    fFile=""
typeset    chSearch="<yoursearchpattern>"

<process producing list of dirs, one per line> |\
while read fDir ; do
     lFound=0
     ls "$fDir" | while read fFile ; do
          if [ lFound -eq 0 ] ; then
               grep "$chSearch" "${fDir}/${fFile}"
               if [ $? -eq 0 ] ; then
                    lFound=1
               fi
          fi
     done
done

I hope this helps.

bakunin

1 Like

And the template I provided in post #4 in the thread Need Linux equivalent for UNIX did exactly that. It includes tested, working code (although it did make a lot of assumptions about things you left unspecified). Did you try starting with that template? What didn't work when you used that template?

And the command:
find * -prune -type d | sort -r -n
gives you directories in reverse alphabetic name order; not reverse order by modification time (assuming that your directory names start with "fd" as in your previous thread's example).

1 Like

Don is right, i haven't even bothered to look at that. What's more, "sort -rn" sorts in reverse numerical order and for a list of directory names this is (usually) nonsense. Remove "-n" because it does nothing at best and not what you want at worst.

Sometimes, i'd like to add, it is a good idea to read the man pages. Not, because everybody keeps telling you that, but because reading these with the intention to understand them is the speed lane to not having to open such threads. With that amount of posts under your belt you should have learned at least the basics of script programming - if you ever had the intention to do so, that is.

I hope this helps.

bakunin