Multi-trap key question

Hello all. I have need two traps on the same command. I have the trap on control-c working. I tried control-z, it didn’t work. One trap exits the script. The other trap continues to the next loop (next drive). The code for the loop through all mswin drives is complex. So, this is a simplified version what I need to do.

scanvirus_cancel_trap='false'
scanvirus_skip_trap='false'


control_c()
# run if user hits control-c
{
  scanvirus_cancel_trap='true'
}
 
# trap keyboard interrupt (control-c)
trap control_c SIGINT

clamscan -r /

if  scanvirus_cancel_trap = 'true' ];then
  printf 'exiting...'
  exit
fi

if  scanvirus_skip_trap = 'true' ];then
  printf 'skip to next drive...'
  continue
fi

I do not see any control-z in script you posted.

I tried control-z in script. It didn’t work. All online sources said it wouldn’t work. What other signal/key will stop clamscan and allow me to trap it?

Control-c stops the scan and I can detect it.

Just a thought…

Why do you need to write different traps?

A possible alternative to what you’re now doing is to write individual functions (ie individual apps) so that your overall app is modularized, then write a “master script” that runs individual functions in some order.

The idea is that if, for instance based on what you appear to be trying to do, you do a standard “CTL-C” killing the process during a print function, your master script would continue to the next function.

Along this line of thought of architecting your application in a modern, “modular” way you might consider

  • Some languages are better suited to providing the individual functionality and the glue
  • If you adopt a language, you will often find “fremeworks” for that language which will provide organization and structure, and enhance re-usability of code.
  • At least in the beginning, you may find that using an IDE can greatly get you up to speed. Although some frameworks have some kind of quickstart default setup, an IDE will not only provide that but also a visual tool. Some IDE will even autocomplete for you, reducing typos and other mistakes while also doing easy library lookups.
  • Another benefit of using a proper language is that there will in almost all cases be useful tools to verify the integrity of your code, easily compile or run, test, minimize, obfuscate, and lots, lots more. Some tools will handle all the workflow in your app, or the workflow of creating your app. In other words, today’s Developer has choices to use tools that even manages and co-ordinates other tools.

If you do settle on a language, you might check whether a Meetup or other User Group for that topic exists in your area, it’s a good place to not only learn and understand quickly, who knows you might find a partner for your project.

TSU

Control-c exits the scanvirus script. In the scan ‘-w’ command, it will scan all mswin drives. Control-c stops clamscan, umounts the drives, and exits the script.

Now, I need control-(key) to skip to the next drive. Stop clamscan and skip to the next drive. I’d show the code, but i’m still fixing other sections of the code.

I figured out how to do it with only control-c. I’d like to try with two control-keys instead.

Language? You mean bash script? It’s already modular, functions to do tasks.

Am referring to various coding languages commonly used which may start with but of course does not end with

javascript, python, perl, ruby, java, c+, c#, …

Efficient coding is based on the idea of re-usable blocks of code that requires minimal testing, structure and centralized configuration (and plenty more principles). Re-inventing the wheel is to be avoided, if there are common ways things are done, that is not something to be avoided.

TSU

I very experienced in programing, the older languages: ADA,PASCAL, ASSEMBLY(6502), ATARI 8-BIT(MAC65, ACTION!). The modern is: ‘C’. I’m expanding to bash script. All the general programing skills i’v mastered(structured programing, debugging, data structures, pointer variables, etc). Recursion: still don’t understand. It’s only the specific command usage for tasks I need to learn. Also, I have limited time to work on it. Back to the task:

Can you do one than trap for different tasks? I have control-c to cancel out and unmount the drive. I need a trap key to cancel the “clamscan” task and move to next drive. I have to go back and fix other unrelated code before I post it. Thanks.

It would if commands started by your shell ignored SIGTSTP. Of course it means you won’t be able to suspend your script, but you won’t be able to do it anyway if you will redefine SIGTSTP handler.

Your description suggests to me that currently you are executing all scans of your drives as one task,
And,
The problem you want to overcome suggests to me that you should instead create scan tasks for each drive individually, and load them into a master script where if the task to scan any drive is killed(not the entire scanning), then your master script would proceed to the next task which contains scanning the next drive.

If there is any kind of limitation to this approach, it’s that your tasks are loaded and must run sequentially(I have not seen this restriction when coding in modern languages).
Note also that if your individual scans were defined or run separately, each could also contain their own scoped methods for things like unique options and even killing the task.

Also, even though you are coding in BASH, it might help to apply some modern concepts like MVC (Model-View-Controller) which separates your code into completely separate code that provides the UI, data, and the functional code the UI touches to interact with the data.

IMO and HTH,
TSU

It uses ‘blkid’ to show all drives, reads the data, and scan drives. The script code improves on clamscan command, adding multi-drive logging later, mswin only. It has only one dependency, ‘clamscan’, it’s engine. It’s a self-contained script, no libraries needed and standard linux commands. At the end of the code, posted a last release.

If there is any kind of limitation to this approach, it’s that your tasks are loaded and must run sequentially(I have not seen this restriction when coding in modern languages).
Note also that if your individual scans were defined or run separately, each could also contain their own scoped methods for things like unique options and even killing the task.

Control-c stops the ‘clamscan’ command, unmounts the drive, and exits the script. Lets the user cancel it. Control-(key) skips to the next drive. Other option, I can add a read key to choose ‘cancel or skip drive?’. The UI can always use improvement.

Parallel processing? I’m trying to make the code as simple as possible. Also, I’m going to disable suspend and other trap signals, still figuring that out.

Also, even though you are coding in BASH, it might help to apply some modern concepts like MVC (Model-View-Controller) which separates your code into completely separate code that provides the UI, data, and the functional code the UI touches to interact with the data.

I’m still trying to master BASH. Parallel process coding isn’t part of my skill set, not that it isn’t something I want to learn later. Two, it meant to be a self-contained script, no libraries, simple to use, and standard linux commands. You can copy it off my post, paste it into a file, make it executable, and your ready to run. My instructions need some work. The new version makes dated directory, stores viruses found there, and put the log of all drives scanned.

clamscan engine, script scanvirus:
‘scanvirus -w’
‘scanvirus -l’
‘scanvirus -m -w’

The above is the reason I made it. Simple to use, scanvirus does all the work. No install, No libraries, just run on the superuser command line. This version is out of date. I’v fixed most of the usage problems and added a better logging system, better than clamscan does. Not to brag. :wink: I’m doing system recovery now. So, it will be a while before I come back to it.

 
#!/bin/bash
#: Title       : scanvirus
#: Date Created: Thu Sep 2 19:27:00 PST 2010
#: Last Edit   : Tue Feb 23 2:30:00 PST 2016
#: Author      : Lord Valarian #: Version     : 2.0.0  beta2
#: Description : virus scanning application, clamscan engine

#<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.
#Software License: http://creativecommons.org/licenses/by-nc-nd/4.0/

#modified for personal use only, no modified uploads permitted, non-commercial use only

#Open bin folder
#Place this file inside "/home/bin/"
#
#Right-click on scanvirus
#Click on properties
#Click on permissions
#Check executable and click ok

#install clamav or run setup
#Click Control -> Tools -> Open Terminal
#Enter termal command:  scanvirus --setup
#Enter admin password, wait for it to finish. Don't close terminal.

#kdeicon disabled
#Enter terminal command:  scanvirus --kdeicons
#close terminal windows
#
#Click on either desktop icon to scan

#Warning!  only use control-c to exit


Create_KDE_linux_scan_icon() {
  cat > ScanVirus_KDE_Linux_Scan.desktop <<EOF
#!/usr/bin/env xdg-open
[Desktop Entry]
Comment[en_US]=
Comment=
Exec=sh scanvirus -linux
GenericName[en_US]=
GenericName=
Icon=kde
MimeType=
Name[en_US]=ScanVirus - linux anti-virus scan
Name=ScanVirus - linux anti-virus scan
Path=$PATH
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=
X-SuSE-translate=trueEOF
EOF

#set file permissions
chmod 744 ScanVirus_KDE_Linux_Scan.desktop
}


Create_KDE_windows_scan_icon() {
  cat > ScanVirus_KDE_Windows_Scan.desktop <<EOF
#!/usr/bin/env xdg-open
[Desktop Entry]
Comment[en_US]=
Comment=
Exec=sh scanvirus -mswin
GenericName[en_US]=
GenericName=
Icon=kde
MimeType=
Name[en_US]=ScanVirus - windows anti-virus scan
Name=ScanVirus - windows anti-virus scan
Path=$PATH
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=
X-SuSE-translate=true
EOF

#set file permissions
chmod 744 ScanVirus_KDE_Windows_Scan.desktop
}

Virus_Vault_Directory_Check()
{
     #create tmp directory if not present
     if  -d "/tmp" ]; then
        printf "root/tmp/ directory present
"
     else
        printf "creating tmp directory
"
        mkdir tmp
        #chmod 744
     fi

     #create virus Vault if not present
     if  -d "/tmp/VirusVault" ]; then
        printf "root/tmp/virusvault/ present
"
     else
        printf "creating virus vault
"
        mkdir /tmp/VirusVault
        chmod 744 /tmp/VirusVault
     fi
}


Scan_Results_Filter()
{

    Line=''
    IFS=''
 
    delete_line_flag=true
    scan_results_flag=false
    
    while read -r -N 1 c; do
    
        if  "$delete_line_flag" = 'true' ]; then
           Line=''
           echo -en "\E[2K\r"
           delete_line_flag=false
        fi

        #if not newline character
        if [[ "$c" != $'
' ]] ; then
            printf "%s" $c
            Line+=${c}
            #printf "(%s)
" $Line
          
            if  "$c" = ':' ];then
               Line=''
            fi

        #if new line
        else
           
           if  "$Line" = '----------- SCAN SUMMARY -----------' ]; then
                scan_results_flag=true
           fi

           if  "$scan_results_flag" = 'true' ]; then
              printf "
"
              Line=''
           
           elif   "$Line" == *"FOUND"* ]] ||  "$Line" == *"moved to"* ]];then
              printf "
"
              Line=''

           else
              delete_line_flag=true
           fi
        fi

    done

    unset IFS
}



#read -p "Done. Press any key..." -n1 -s;printf "";

#####################
# shortcut code for clamscan #
#####################

control_c()
# run if user hits control-c
{
  printf 'Exiting...
'
  scanvirus_trap_flag='true'
  #kill clamscan
}

    #export TERM=vt100

    #trap keyboard interrupt (control-c)
    scanvirus_trap_flag='false'
    trap control_c 2

    #commands
    if  "$1" = "-mswin" ] ||  "$1" = "-w" ]; then
       Virus_Vault_Directory_Check;
       freshclam
         
       printf "
.....scanvirus mswin.....
"
         
    
       #blkid -o list
       scanvirus_flag="false"
       while read -ra line; do 
          if  "$scanvirus_flag" = 'false' ]; then
            scanvirus_flag="true"
            read -ra line
            read -ra line
            #break
          fi
        
          Device_Label=${line[0]}
          File_System=${line[1]}
          Drive_Label=${line[2]}
          Mount_Point=${line[3]}

          #if file system vfat or ntfs
          if  $File_System = 'ntfs' ] ||  $File_System = 'vfat' ]; then
            #printf "%s %s %s %s
" ${line[0]} ${line[1]} ${line[2]} ${line[3]}

            printf "__________________________________________________
"

            #if device not mounted
            if  $Mount_Point = '(not' ]; then
            #udisksctl mount -b $devicename -o ro
            Device_Mounted_Flag=true
                 
                 while read -ra command_output; do
                   printf "%s %s %s %s
" ${command_output[0]} ${command_output[1]} ${command_output[2]} ${command_output[3]%.}
                   break
                 done < <(udisksctl mount -b "$Device_Label")     
                 command_output_mount=${command_output[0]}
                 
                 if  "$command_output_mount" = 'Mounted' ]; then
                    printf "%s mounted
" $Drive_Label
                 else
                   printf "Error: mount %s
" $Drive_Label
                 fi
                 command_output_scandir=${command_output[3]%.}
                
            #elif  "${line[3]}" = '(in' ]; then
            #     printf "(in use)
" 
            else
                 Device_Mounted_Flag=false
                 command_output_scandir=$Mount_Point
            fi
       
            #scan only or move files
            if  "$2" = "-m" ] ||  "$2" = "-movetovault" ]; then
                 printf "Move to Virus Vault: /tmp/VirusVault/
"
                 Movefile_Parm="--move=/tmp/VirusVault"
            else
                 Movefile_Parm=''
                 printf "Scan only
"
                 #printf "
"
            fi

            printf "
scanning: %s %s

" $Drive_Label $command_output_scandir
            
            clamscan -r $command_output_scandir $Movefile_Parm --follow-dir-symlinks=0 --follow-file-symlinks=0 | Scan_Results_Filter

            #if drive mounted, unmount it
            if  "$Device_Mounted_Flag" = 'true' ];then
               while read -ra command_output; do
                 break
               done < <(udisksctl unmount -b "$Device_Label") 
               command_output_unmount=${command_output[0]}
               
               if  "$command_output_unmount" = 'Unmounted' ]; then
                 printf "%s unmounted
" $Drive_Label
               else
                 printf "Error: unmount %s
" $Drive_Label
               fi
            fi
            printf "__________________________________________________
"
          fi

          #break
         
          if  "$scanvirus_trap_flag" = 'true' ]; then
             break
          fi
        
       done < <(blkid -o list)
       
       #virus vault files read only
       chmod 744 /tmp/VirusVault
       
    elif  "$1" = "-linux" ] ||  "$1" = "-l" ]; then
         printf ".....Scanning linux.....
"; 
         freshclam
         printf "
"
         clamscan -r / --exclude-dir=/sys --exclude-dir=/proc --exclude-dir=/dev --exclude-dir=/.snapshots --follow-dir-symlinks=0 --follow-file-symlinks=0 | Scan_Results_Filter
 
    elif  "$1" = "-help" ] ||  "$1" = "-h" ]; then

        printf "
Scan Virus
help commands
-------------
virus scan linux files
     p1: -l or -linux  
virus scan windows files
     p1: -w or -mswin 
     p2: -m or -movetovault (optional)
--setup:  setup scanvirus
--kdeicons:  setup icons

"           

    elif  "$1" = "--setup" ]; then
        printf "
"
        printf "ScanVirus Setup...
"
        su -c "zypper --non-interactive install clamav;chkconfig freshclam on;freshclam;exit"
        printf "
"

    elif  "$1" = "--kdeicons" ]; then
            #Create_KDE_linux_scan_icon;
            #Create_KDE_windows_scan_icon;  
            #printf "KDE Icons Created
";
            printf "Disabled
";

    else
        printf "
Scan Virus
help commands
-------------
virus scan linux files
     p1: -l or -linux  
virus scan windows files
     p1: -w or -mswin 
     p2: -m or -movetovault (optional)
--setup:  setup scanvirus
--kdeicons:  setup icons

"           
    fi
exit 0
# End Of Script

No parallel processing.
But, might be described as “hierarchical processing” since only one task is actively running at a time. “Worker” tasks are managed and run by a “master task.”
Specific to your question, each Worker task should include its own code for exception handling so that when something like a CTL-C is invoked, only that Worker task will receive the input and act accordingly.

Is typical of modern coding, the idea that a single, enormous piece of code is not the right approach.

TSU

My main linux drive is in use for file recovery. However, I now have a linux flash drive to use for now to test the script (file recovery output drive).

As to having a file as list of drives to be scanned(drives.conf), I tried it and it was impractical. I like the simplicity of scanvirus, just a minimum number of commands to remember (1 command and 1 command + option). It does all the work of finding drives/partitions, scanning each, creating folders for drives as their scanned, moving found viruses to the folder, and writing a practical log to the folder.

Using control-(key) to skip drives, it not to practical for someone in a hurry and can’t stay in the room. A simple drive mask command would be a better, a positive or negative mask. Coding more than one mask will be hard, but not impossible. You would need to use ‘blkid -o list’ to find a search parm. I could include a short cut command, ‘scanvirus -p-d]’ list drives/partitions’. The drive label or device name that can be searched for the mask(blkid -o list).

scanvirus -w -pm mask1] -nm mask1]

This would filter out(negative/in(positive) any drives with masks.

Scanvirus: A ‘Simplified Command Line User Interface’(SCLUI) using ‘clamscan’ as it’s engine.

Make text file ‘scanvirus’. Copy code and paste to ‘scanvirus’. Set execute flag on scanvirus. Enter terminal superuser mode. Enter ‘scanvirus --help’. Your ready. :slight_smile:

FYI, I’m going to add the ability to scan linux format flash drives, a better system than now. I’m going to use the same method as mswin scan. I’m currently rebuilding it, putting new features back in, structured logging and virus storage. A few more commands, still keeping it a very limit set of commands. Finally created a name for i’m doing. :wink:

I’v decided on a completely different design to solve the problem. Thanks to all for the help.