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
1 Answer 1
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