Variable scop ksh vs bash

I am not clear why the cnt variable is not increased in the script below:

 #!/bin/bash
INPF=${1:-a.txt};
KWDS=${2:-lst}
cnt=0;
grep -v '^#' $KWDS | while read kwd;
do
        grep -q $kwd $INPF;
        if [ $? -eq 0 ]; then
                echo Found;
                ((cnt=cnt+1));
        fi
done
echo $cnt;
 

The files for input:

 /tmp$ cat a.txt 
ABC
XYZ
abc
xyz
/tmp$ cat lst
123
qwe
abc
zxc
 

when I run script I get:

 Found
0
 

When I change to Korn shell by using #!/bin/ksh instead script works as expected and I see result as

Found
1

Why is that? does it mean under bash the scope of cnt variable outside while loop is not the same as cnt inside the wihile loop?
Just in case, the bash is:

bash --version
GNU bash, version 3.2.39(1)-release (i486-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.

Clarification will be appreciated.

It's not a question of "scope" exactly, code running behind a pipe runs in a completely different process. It gets a copy of the current values of the parent's variables when it's created. Changes aren't shared.

KSH and everything-except-KSH consider pipes in the opposite direction:

# KSH
subshell | local-shell

# Bourne-compliant SH
local-shell | subshell
1 Like

Also, for bash try any of these:

POSIX?  : cnt=$(( $cnt +1 ))
POSIX?  : cnt=$[ $cnt + 1 ]
C-style : ((cnt++))

hth

EDIT:
Also, there are way too many unrequired line-ending-semi-colons - C, php or java? :wink:
Piping looks properly for bash.

1 Like

The current POSIX standards specify arithmetic expansions:

cnt=$(($cnt + 1))
      and
cnt=$((cnt + 1))

They do not specify cnt=$[ $cnt + 1 ] .
There is a proposal to include ((cnt++)) in the next revision of the POSIX standards, but it isn't required yet.

Recent bash provides "process substitution", see man bash . Try

INPF=${1:-file1};
KWDS=${2:-file2}
cnt=0;
while read kwd;
        do grep -q $kwd $INPF;
           if [ $? -eq 0 ]; then
                echo    Found;  
                ((cnt=cnt+1));
           fi
        done  < <(grep -v '^#' $KWDS) 
echo $cnt;

With recent bash releases, you can use the lastpipe option which was finally implemented to provide ksh behavior:

#!/bin/bash
shopt -s lastpipe
INPF=${1:-a.txt}
KWDS=${2:-lst}
cnt=0
grep -v '^#' $KWDS | while read kwd
do
        grep -q $kwd $INPF
        if [ $? -eq 0 ]; then
                echo Found
                ((cnt=cnt+1))
        fi
done
echo $cnt

Result:

Found
1
1 Like