varible being erased with no cause

This is part of my scanvirus script. I need to expand the logging. The code around is complex, but just look at the small additions.

I’m baffled as why this this variable is clearedl. This is a short clear var, apend var, and print var. It’s very simple, yet won’t work! ARG! There is no logic to this varible being cleared. Need help

#partition_scan ostype moveflag partition1 partition2 partitionx
partition_scan()
{
        OStype="$1"
        Move_Flag="$2"
        Partition_Log=''; mod start var null

        #delete first two parms
        shift 2
            
        Current_Vault_Folder="$Virus_Vault_Folder/$OStype "
        Current_Vault_Folder+=$(date +'%m-%d-%Y %I:%M:%S%P')
        mkdir "${Current_Vault_Folder}"
         
        printf "
.....scanvirus %s.....
" $OStype | tee "$Current_Vault_Folder/scanresults.log"
  
        IFS=':'
        blkid | sed 's/: /:/g' | sed 's/\" /:/g' | while read -ra line
        do
            Device_Label=''
            File_System=''
            Drive_Label=''
            Mount_Point=''

            Device_Label=${line[0]}
            for blkid_field in ${line
[li]}[/li]            do
                if  [[ "$blkid_field" == "TYPE="* ]];then
                    #cut 'type='
                    File_System=${blkid_field#*\"}
                elif  [[ "$blkid_field" == *"LABEL="* ]];then
                    #cut 'label='
                    Drive_Label=${blkid_field#*\"}
                fi
            done
         
            #cut /dev/
            Temp_MP=${Device_Label#/*/}    #printf "Temp_MP= %s
" ${Temp_MP}

            #                                                               cut devicename
            Mount_Point=$( lsblk -l -o name,mountpoint | grep "${Temp_MP}" | sed "s/${Temp_MP} //g" )

            #cut leading spaces
            Mount_Point=${Mount_Point#   }

            #printf "
"
            #printf "Device_Label= '%s'
" $Device_Label
            #printf "File_System = '%s'
" $File_System
            #printf "Drive_Label = '%s'
" $Drive_Label
            #printf "Mount_Point = '%s'
" $Mount_Point

            #scan for matching partition types in parms
            Found_Match=false
            for parm;
            do
                #printf "FS= %s:parm= %s  " $File_System $parm
                #if [ "$File_System" = "$parm" ];then
                #    printf "true
"
                #else
                #    printf "false
"
                #fi

                if [ "$File_System" = "$parm" ];then
                    Found_Match=true
                fi
            done

            #if file system match
            if [ "$Found_Match" = 'true' ]; then
 
                #if [ "$Drive_Label" = "System Reserved" ]; then
                    #printf "Skipping System Reserved...
"
                    #continue
                #fi

                Partition_log+="$Drive_Label"; mod append to string
                printf "Partition_log=%s
" $Partition_log; mod string apend added successfully
                
                printf "__________________________________________________
" | tee -a "${Current_Vault_Folder}/scanresults.log"

                Device_Mounted_Flag=false
            
                #if device not mounted
                if [ "$Mount_Point" = '' ]; then

                    command_output_scandir=$(udisksctl mount -b "$Device_Label");mount_error=$?
                    command_output_scandir=${command_output_scandir%.}
                    printf "%s
" $command_output_scandir
                
                    #cut out scan directory
                    command_output_scandir=${command_output_scandir#Mounted\ *\ at\ }
                    Mount_Point=$command_output_scandir
                
                    #printf "%s
" $Mount_Point
                 
                    if [ "$mount_error" != 0 ]; then
                        printf "Error: mount %s
" $Drive_Label
                    else
                        Device_Mounted_Flag=true
                    fi
                fi

                printf "
scanning: %s %s
" $Drive_Label $Mount_Point | tee -a "${Current_Vault_Folder}/scanresults.log"

                # trap keyboard interrupt (control-c)
                trap "control_c $Device_Mounted_Flag $Device_Label" exit
                
                #scan mswin and linux differently
                if [ "$OStype" = 'linux' ]; then
                    clamscan -r "$Mount_Point" --exclude-dir=/sys --exclude-dir=/proc --exclude-dir=/dev --exclude-dir=/.snapshots --follow-dir-symlinks=0 --follow-file-symlinks=0 --cross-fs=no | Scan_Results_Filter
    
                elif [ "$OStype" = 'mswin' ]; then
                    #scan only or move files
                    if [ "$Move_Flag" = 'true' ]; then
                        printf "Move to Virus Vault: /var/log/VirusVault/
"
                        clamscan -r "$Mount_Point" "--move=${Current_Vault_Folder}" --follow-dir-symlinks=0 --follow-file-symlinks=0 --cross-fs=no | Scan_Results_Filter
                    else
                        printf "Scan only
"
                        clamscan "$Mount_Point" --follow-dir-symlinks=0 --follow-file-symlinks=0 --cross-fs=no | Scan_Results_Filter
                    fi
                    #printf "movefile_parm= %s
" $Movefile_Parm
                fi

                #if drive mounted, unmount it
                if [ "$Device_Mounted_Flag" = 'true' ];then
                    #flush buffers to make sure all the data is written to drive
                    sync -f "$Device_Label"

                    command_output_unmount=$(udisksctl unmount -b "$Device_Label");unmount_error=$?
                    printf "%s
" ${command_output_unmount%.}    
                fi
                printf "__________________________________________________
" | tee -a "${Current_Vault_Folder}/scanresults.log"
            fi

            #printf "next loop
"
         
            if [ "$scanvirus_trap_flag" = 'true' ]; then
                break
            fi
            
        done

        printf "Partition_log=%s
" $Partition_log;  mod print string   string is null, but it's not being cleared by any code.

        #virus vault files read only
        #chmod 744 "${Current_Vault_Folder}"
}


Congratulations! You have found one of the most-annoying things I’ve
found with regard to variables and loops that have data piped into them.

I first found this when trying to read a file using:


cat $file | while read oneline; do ... done

I liked this form because it was clear, from the top of the loop, what was
being read.

I had to change my code to just use a redirect to read the file, and then
the problem was solved, or so I remember it, but that requires having the
redirect in at the end of the loop, so it seemed less-obvious to me, but
the variables within the loop then maintained their values. Frustrating,
I know, but it’s the way the system works, and it is (as I recall) because
you are invoking a sub-shell when you do it your/my-original way, and that
sub-shell dies when the loop ends, so all variables within also die. Stop it.

http://mywiki.wooledge.org/BashFAQ/024

Having found this issue, you are now an expert script person. Congrats!


Good luck.

If you find this post helpful and are logged into the web interface,
show your appreciation and click on the star below.

If you want to send me a private message, please let me know in the
forum as I do not use the web interface often.

Can you show the line(s) where the problem is? This app is a beast to understand and I wrote it. :stuck_out_tongue:

Well, yes; I am sorry I was not clear the first time.

Your variable is only within one loop, and that is the only while loop,
and the line starting it looks like this:


blkid | sed 's/: /:/g' | sed 's/\" /:/g' | while read -ra line

Since you are piping data from a command, instead try to read it in from a
file, which probably means write this command’s output to a file and then
redirect it in:


TMPFILE=$(mktemp);
blkid | sed 's/: /:/g' | sed 's/\" /:/g' > "${TMPFILE}";
while read -ra line; do
#Stuff goes here
done < "${TMPFILE}
rm "${TMPFILE}";

Let us know how it goes.


Good luck.

If you find this post helpful and are logged into the web interface,
show your appreciation and click on the star below.

If you want to send me a private message, please let me know in the
forum as I do not use the web interface often.

More details.

https://unix.stackexchange.com/questions/181937/how-create-a-temporary-file-in-shell-script

(Continued)

With a bit a tweaking, the new log works. Add what drives what you have scanned in an mswin scan.

However, I found it seemed to cause a bug or found one in the trap system. It also uncovered a bug in the drive search for mswin partition. For some reason, it’s adding a quote into the drive label. NTFS → NFTS". Both bugs will take time to fix.

Sometimes, I just want to hit this computer with a sledgehammer! :stuck_out_tongue:

Thanks for the help.

This topic piqued my interest.

So, some more possibilities although I consider ab’s wooledge.org reference excellent…

This topic is described similarly but in different words in the TLDP’s page on subshells
http://tldp.org/LDP/abs/html/gotchas.html#SUBPIT

Both the Parent/Child subshell variable issue and LOOPs are described in the TLDP’s “Gotcha” Bash scripting page with some additional suggestions
http://tldp.org/LDP/abs/html/gotchas.html#SUBPIT

The following first answer recommends the “Command Grouping” method
https://unix.stackexchange.com/questions/140043/how-to-make-a-variable-from-a-subshell-available-in-the-parent-shell

But, the second answer in the above link is most natural to me, because it’s the approach of most of today’s OOP… Defining individual functions. You should have no problem passing the result of a function to something else, even updating a global variable. Also, this type of structure should solve your problem of “beastly” code, making your code easy to read and easy to understand even with limited comments.

Interesting stuff…
TSU