3
\$\begingroup\$

This is my first Bash script and I decided to use what I've learned so far to help manage stray processes while I develop in my *nix environs.

I've tested the script extensively and it seems to work (there may be some things I have not caught yet).

If I could get some critiques/tips on the script that would be great.

I named the file process and placed it in my ~/bin folder so that I could execute it like any other program.

#!/bin/bash
# kill processes using SIGQUIT signal -- still in testing
PROGNAME=$(basename 0ドル)
function _usage_notice {
 echo "Usage: $PROGNAME [ help | show | destroy ] [ arg(s)... ]"
}
function _usage_summary {
echo "Usage: $PROGNAME [ action ] [ arg(s)... ]
 Summary
 -------
 This script is designed to send a quit signal event to a
 running program. If multiple instances of that program
 exist, they are all sent the same signal.
 Action Description
 ------ -----------
 show Shows current processes for current user.
 kill
 destroy Sends SIGQUIT signal to given process if
 given process exists.
 help Outputs this help text.
"
}
function _usage_processes {
echo "Usage: $PROGNAME [ show ] [ user | root | unsorted | sorted | less ]
 Examples
 --------
 $PROGNAME show
 Executes 'ps' with the format 'pid,user,comm'
 $PROGNAME show user
 Executes 'ps' and outputs 'user' owned processes
 $PROGNAME show root
 Executes 'ps' and outputs 'root' owned processes
 $PROGNAME show [ unsorted | all ]
 'all' and 'unsorted' are synonymous and displays all processes
 $PROGNAME show sorted
 Executes 'ps' and outputs 'all' processes in sorted order by user
 $PROGNAME show less
 Executes 'ps' and pipes 'all' output to 'less' if 'less' exists
"
}
function _usage_destroy {
echo "Usage: $PROGNAME [ destroy ] [ command(s)... ]
 Examples
 --------
 $PROGNAME destroy nautilus
 Sends the SIGQUIT signal to the process 'nautilus'
 $PROGNAME destroy [ program(s)... ]
 You can pass multiple programs all at once as well.
 $PROGNAME destroy nautilus bash pithos firefox
 Sends the SIGQUIT signal to given processes
"
}
function _usage_help {
echo "Usage: $PROGNAME [ help ] [ show | destroy | help ]
 Examples
 --------
 $PROGNAME
 Outputs basic usage
 $PROGNAME help
 Outputs usage summary
 $PROGNAME help [ show | destroy | help ]
 Outputs usage information for given action
"
}
function _usage_full {
 case 1ドル in
 "show") _usage_processes ;;
 "destroy"|"kill") _usage_destroy ;;
 "help") _usage_help ;;
 *) echo "Invalid argument given to action help." ;;
 esac
}
# test if a valid action was given
function _is_valid_action {
 case 1ドル in
 "destroy"|"kill") echo valid ;;
 "show") echo valid ;;
 "help") echo valid ;;
 *) echo "" ;;
 esac
}
# test if action has no arguments
function _input_is_empty {
 while [[ 0 -lt "$#" ]]; do
 if [[ -n $(_is_valid_action 1ドル) ]]; then
 shift
 if [[ -n $(_is_valid_action "1ドル") ]]; then
 echo valid
 break
 fi
 continue
 elif [[ -n "1ドル" ]]; then
 echo valid
 break
 else
 echo ""
 break
 fi
 done
}
# show current processes according to given arguments
function _processes {
 case "1ドル" in
 "user") ps -U $USER -o pid,tty,user,comm ;;
 "root") ps -U root -o pid,tty,user,comm ;;
 "all"|"unsorted") ps -A -o pid,tty,user,comm ;;
 "sorted") ps -A --sort=user -o pid,tty,user,comm ;;
 "less") if [[ -n $(which less) ]]; then
 ps -A --sort=user -o pid,tty,user,comm | less
 else
 echo "'less' is not installed."
 fi ;;
 *) ps -o pid,user,comm ;;
 esac
}
# send to quit signal to given processes
function _destroy {
 while [[ 0 -lt "$#" ]]; do
 pid=$(pgrep 1ドル)
 if [[ -z "$pid" ]]; then
 echo "Process '1ドル' does not exist."
 exit 2 
 fi
 for item in $pid; do
 kill -SIGQUIT $pid 
 echo "Destroyed process '$item' named '1ドル'"
 done
 shift
 done
}
function _prompt {
 echo "Warning! This function uses pattern matching!"
 echo "This is DANGEROUS because multiple processes may be selected!"
 read -p "Are you sure you want to continue? [y/yes/n/no]> " answer
 case $answer in
 "y"|"yes") clear
 echo "You were Warned! Starting in 5 seconds..."
 sleep 5 
 return ;;
 "n"|"no") exit 2 ;;
 esac
}
case 1ドル in
 "show") 
 shift
 _processes "$@"
 ;;
 "destroy"|"kill") 
 if [[ -z $(_input_is_empty "$@") ]]; then
 echo "No arguments were given to destroy."
 exit 1
 fi
 shift
 _prompt
 _destroy "$@"
 ;;
 "help") 
 if [[ -z $(_input_is_empty "$@") ]]; then
 _usage_summary
 exit 0
 fi
 shift
 _usage_full "$@"
 ;;
 *) # default
 _usage_notice 
 exit 1 
 ;;
esac
exit 0
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Apr 27, 2016 at 1:25
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

First of all, it's very nice that you have separated each distinct functionality into functions, nicely done. Some improvements are possible.

Use the exit code, Luke

This function prints "valid" if the input is valid, or empty string if invalid:

function _is_valid_action {
 case 1ドル in
 "destroy"|"kill") echo valid ;;
 "show") echo valid ;;
 "help") echo valid ;;
 *) echo "" ;;
 esac
}

It would be better to use the exit code instead, like this:

function _is_valid_action {
 case 1ドル in
 destroy|kill|show|help) return 0 ;;
 *) return 1
 esac
}

You will need to change the callers accordingly. Instead this:

 if [[ -n $(_is_valid_action 1ドル) ]]; then

Change to:

 if _is_valid_action 1ドル; then

Which happens to be simpler.

Adjust _input_is_empty following the same logic.

Double-quote path variables

It's recommended to double-quote all path variables to prevent globbing and word splitting, for example here, put 0ドル in "0ドル":

PROGNAME=$(basename 0ドル)

No need to double-quote literal strings

In this code, the double-quoting is a bit awkward for the cases:

 case 1ドル in
 "show") _usage_processes ;;
 "destroy"|"kill") _usage_destroy ;;
 "help") _usage_help ;;
 *) echo "Invalid argument given to action help." ;;
 esac

You could write simpler as:

 case 1ドル in
 show) _usage_processes ;;
 destroy|kill) _usage_destroy ;;
 help) _usage_help ;;
 *) echo "Invalid argument given to action help." ;;
 esac

Minor things

It's not a problem, it's just a bit unusual to print large multiline blocks of text using echo. It can get troublesome if you need to embed double-quotes. The commonly used alternative is a here document, like this:

cat << EOF
Usage: $PROGNAME [ destroy ] [ command(s)... ]
 Examples
 --------
 $PROGNAME destroy nautilus
 Sends the SIGQUIT signal to the process 'nautilus'
 $PROGNAME destroy [ program(s)... ]
 You can pass multiple programs all at once as well.
 $PROGNAME destroy nautilus bash pithos firefox
 Sends the SIGQUIT signal to given processes
EOF
answered May 14, 2016 at 5:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.