Variable loses value outside loop

Hi,

I am looking for a global variable found_flag to be set a value that can be accessed outside the loop anywhere in the bash shell script.

 more test.sh
 found_flag=0
 searchdir=/web/bea_apps/applications
  
 find . -type f \! -name tasty.tar | $AWK -F/ '{print $NF}' | while IFS= read -r entry; do
  
 found_flag=0
 find $searchdir -type f -name $entry | grep -v LOGS | while IFS= read -r second_entry; do
  
 mv $second_entry $second_entry.$NOW.bkp
 cp -R $entry `dirname $second_entry`/
 found_flag=1
 echo "Displaying the value of found_flag:$found_flag"
  
 done
  
 echo "Displaying the value of found_flag outside while loop:$found_flag"
  
 done
 

Output: bash -x test.sh

 
 + find . -type f '!' -name client.tar
 + /usr/xpg4/bin/awk -F/ '{print $NF}'
 + IFS=
 + read -r entry
 + found_flag=0
 + find /web/bea_apps/applications -type f -name sd.ear
 + grep -v CURRENT
 + IFS=
 + read -r second_entry
 + mv /web/bea_apps/applications/sd.ear /web/bea_apps/applications/sd.ear.10032017.bkp
 ++ dirname /web/bea_apps/applications/sd.ear
 + cp -R sd.ear /web/bea_apps/applications/
  
 + found_flag=1
 + echo 'Displaying the value of found_flag:1'
 Displaying the value of found_flag:1
 + IFS=
 + read -r second_entry
 + echo 'Displaying the value of found_flag outside while loop:0'
 Displaying the value of found_flag outside while loop:0
 

In the RED BOLD output above I am expecting the found_flag to have the value=1 instead of zero.

Can you please suggest a quick way how I can set the value globally so it reflects outside the loop as well ?

Using sub-shells would be my last priority.

Hi,

by piping the output of find/awk/grep to the loop a subshell is created, thats why the variable in the parent shell is unchanged.
Avoid piping to the loop, bash for example offers process substitution that can be used here:

$ cat x.sh
echo piping
a=0
ls *.sh |while read i; do
   echo $i
   a=$(( a + 1 ))
   echo inside: $a
done
echo outside: $a
echo =====
echo process substitution
a=0
while read i; do
   echo $i
   a=$(( a + 1 ))
   echo inside: $a
done < <(ls *.sh)
echo outside: $a

$ ./x.sh
piping
hw.sh
inside: 1
x.sh
inside: 2
outside: 0
=====
process substitution
hw.sh
inside: 1
x.sh
inside: 2
outside: 2

Try setting the lastpipe option in bash

I think ksh operates like this per default...

I'm curious about this:

find . -type f \! -name tasty.tar | $AWK -F/ '{print $NF}' | while IFS= read -r entry; do

And then you search for $entry later ... why not just search for tasty.tar?

How about:

entry=$(find . -name 'tasty.tar' -type f)
if [ ! -f "$entry" ]
then
        echo "tasty.tar not found" >&2
        exit 1
fi

entry=$(basename "$entry")

I m trying this option for a solution.

#!/bin/bash
shopt -s lastpipe

However, I get the below error.

./run.sh: line 2: shopt: lastpipe: invalid shell option name

My bash version is

bash-3.2$ bash --version
GNU bash, version 3.2.57(1)-release (sparc-sun-solaris2.10)
Copyright (C) 2007 Free Software Foundation, Inc.

That version of bash is 10 years old.

You could try using ksh instead.

1 Like