Search code examples
shellloopsawkbreak

for loop do not break in shell script while comparing variable value populated from awk


I am trying to validate data in a file with a pipe delimiter. I still need to work on it for all check conditions. When validation fails, further validation should not happen. Need to skip from a loop. I am unable to determine why the break (or exit) is not working even when the condition is satisfied.

encoding_details variable will have data populated from the configuration table and hold the details of fields for a single file. Based on the configuration, these sets of details will be dynamic for every file.

1-memid-ID|2-memfirstname-NAME|3-memlastname-NAME

The value represents column position - column name - column type

below is the work-in-progress code block. Comments are placed to highlight issues

#!/bin/sh

#initiat variables here

retval=0 #this is a variable related with issue

#get configuration details from the table

encrpt_avoid_flag=Y

#extract all files in loop 
#get part of file_name to related configuration
#start validation for each file

#change directory to work on files now
cd  $directy_with_files;

echo "Initiating a process to read files..."
 
extractfilelist=`ls *.txt 2>/dev/null`; 
for file in $extractfilelist
do 
    #now get details of columns to be encrypted for a file 
    encoding_details=`<populated using sqlquery>`   
    
    if [[ -z $encoding_details ]]
    then
        # lets keep this output in a log file - need to work on it
        echo "WARNING: Encoding details not found for file: ${file}"
        echo "Skipping the file from validation scope..." 
    else 
        IFS="|" read -a encoding_column <<< $encoding_details 

        for column in "${!encoding_column[@]}"
        do 
            IFS="-" read -a encoding_column_detail <<< ${encoding_column[$column]}
            column_order=${encoding_column_detail[0]}
            column_name=${encoding_column_detail[1]}
            encoding_type=${encoding_column_detail[2]}
            
            awk -F'|' -v p_column_order="$column_order" -v p_encoding_type="$encoding_type" -v p_encrpt_avoid_flag="$encrpt_avoid_flag" '
            { 
                if ((p_encoding_type == "ID" || p_encoding_type == "NAME") && p_encrpt_avoid_flag == "Y") 
                { 
                    if ($p_column_order != "Blinded" && p_encoding_type == "NAME")
                    {
                        print 1; #this is an error condtion
                        exit;
                    }
                } 
            }' $file | 
            while read retval
            do
                if [ $retval -gt 0 ]
                then
                    echo "ERROR: encryption failed. Please find details below..."
                    echo "column name    : "$column_name 
                    echo "column position: "$column_order
                    echo "file_name      : "$file
                    exit #this exit do not works
                fi
            done
        if [ $retval -gt 0 ]
        then
            break #issue - this break do not work. while printing values inside the if block $retval shows 1 and output get printed as well
        fi
        done #end for column (encoding_column)
    fi #encoding details check end
    if [ $retval -gt 0 ]
    then
        break #issue - this break do not work here as well. while printing values inside the if block $retval shows 1 and output get printed as well
    fi
done #end of file loop
echo "finally : $retval" #and at then end value printed for retval variable is 0? it was 1 when error occoured

Solution

  • The problem is that all your breaks depend on the value of $retval, which does not exist in the respective scopes. The reason, why exit does not seem to work, is that only the while loop is exited which exists in a separate process which reads the output of awk from stdin. Consider the following minimal example:

    #!/bin/sh
    
    echo 1 | 
    while read retval
    do
        if [ $retval -gt 0 ]
        then
            echo "retval is greater than 0"
            exit # this exits only the while loop which is in a separate process
            echo "This does not print"
        fi
    done
    
    # retval does not exist in this scope
    echo retval: [$retval]
    

    This gives you the following output:

    retval is greater than 0
    retval: []
    

    As you see, exit is exiting the while loop and $retval does not have any value after the code block in question.