Background
Error handling in Bash is little bit difficult.But, “set command” and “trap command” help us to do it.
Environment
- OS
- Linux 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Content
Try-Catch-Finally
set command referencetrap command reference
#!/bin/bash
function main() {
trap catch ERR
echo "[INFO]Main"
return 0
}
function catch() {
echo "[ERROR]Fail"
}
function finally() {
echo "[INFO]Finish"
}
# Entry Point
set -eu
trap finally EXIT
main
The source code result is following.
Error handling check.$ ./main.sh [INFO]Main [INFO]Finish
Add error command to main function and try to run it.
#!/bin/bash
function main() {
trap catch ERR
echo "[INFO]Main"
diff test
return 0
}
function catch() {
echo "[ERROR]Fail"
}
function finally() {
echo "[INFO]Finish"
}
# Entry Point
set -eu
trap finally EXIT
main
Result ist following.
$ ./main.sh [INFO]Main diff: missing operand after `test' diff: Try `diff --help' for more information. [ERROR]Fail [INFO]Finish
Retry
Easy to add retry function with inserting “main” catch function.
#!/bin/bash
function main() {
trap catch ERR
echo "[INFO]Main"
return 0
}
function catch() {
echo "[ERROR]Fail"
echo "[INFO]Retry"
main
}
function finally() {
echo "[INFO]Finish"
}
# Entry Point
set -eu
trap catch ERR
trap finally EXIT
main
Let’s check error handling part with following program which has an error.
#!/bin/bash
function main() {
trap catch ERR
echo "[INFO]Main"
diff test
return 0
}
function catch() {
echo "[ERROR]Fail"
echo "[INFO]Retry"
main
}
function finally() {
echo "[INFO]Finish"
}
# Entry Point
set -eu
trap catch ERR
trap finally EXIT
main
Result is following.
$ ./main.sh [INFO]Main diff: missing operand after `test' diff: Try `diff --help' for more information. [ERROR]Fail [INFO]Retry [INFO]Main diff: missing operand after `test' diff: Try `diff --help' for more information. [INFO]Finish
unit test
You can write unit test with this structure easily.shunit2 will help you. Concrete source code is following.
main.sh
#!/bin/bash
function main() {
trap catch ERR
echo "[INFO]Main"
lib_main
return 0
}
function catch() {
echo "[ERROR]Retry"
main
}
function finally() {
if [ ! $? -eq 0 ]; then
TITLE="error"
TO=abc@example.com
FROM=abc@example.com
echo -e "Please check log file." | mail -s "$TITLE" -r "$FROM" "$TO"
echo "[ERROR]Alert mail is sent to $TO ."
fi
echo "[INFO]Finish"
}
# Entry Point
SOURCE_PATH="$(cd $(dirname $0);pwd)"
source $SOURCE_PATH/lib.sh
set -eu
trap finally EXIT
main
lib.sh
#!/bin/bash
function lib_main() {
echo "[INFO]Lib Main"
touch "test.log"
return 0
}
test.sh
#!/bin/bash
function oneTimeSetUp() {
echo "[INFO]Setup"
source ./lib.sh
}
function testLibMain() {
lib_main
test -e test.log
${_ASSERT_EQUALS_} "TestFileExists" $? 0
}
. "path/to/shunit2/shunit2"
main.sh result is following.
test.sh result is following.$ ./main.sh [INFO]Main [INFO]Lib Main [INFO]Finish
[INFO]Setup testLibMain [INFO]Lib Main Ran 1 test. OK