Обработка ошибок и рекомендации по использованию функций
В этом последнем разделе мы рассмотрим методы обработки ошибок и рекомендации по использованию функций в Bash. Правильная обработка ошибок является ключевым моментом при создании надежных и поддерживаемых скриптов.
Создание скрипта с обработкой ошибок
Давайте создадим новый скрипт, который демонстрирует надежную обработку ошибок:
cd ~/project/bash_functions
touch error_handling.sh
Добавьте следующее содержимое:
#!/bin/bash
## Enable error handling
set -e ## Exit immediately if a command exits with non-zero status
## Define a function to log messages
log_message() {
local level="$1"
local message="$2"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message"
}
## Function to validate a number is positive
validate_positive() {
local num="$1"
local name="$2"
## Check if the argument is a number
if ! [[ "$num" =~ ^[0-9]+$ ]]; then
log_message "ERROR" "$name must be a number"
return 1
fi
## Check if the number is positive
if [ "$num" -le 0 ]; then
log_message "ERROR" "$name must be positive"
return 2
fi
return 0
}
## Function that divides two numbers
divide() {
local numerator="$1"
local denominator="$2"
## Validate inputs
validate_positive "$numerator" "Numerator" || return $?
validate_positive "$denominator" "Denominator" || return $?
## Check for division by zero
if [ "$denominator" -eq 0 ]; then
log_message "ERROR" "Division by zero is not allowed"
return 3
fi
## Perform division
local result=$(echo "scale=2; $numerator / $denominator" | bc)
echo "$result"
return 0
}
## Function to safely get user input
get_number() {
local prompt="$1"
local input
while true; do
read -p "$prompt: " input
if validate_positive "$input" "Input"; then
echo "$input"
return 0
else
log_message "WARN" "Invalid input. Please try again."
fi
done
}
## Disable automatic exit on error for the main script
set +e
## Main script logic
log_message "INFO" "Starting division calculator"
## Test with valid values
result=$(divide 10 2)
exit_code=$?
if [ $exit_code -eq 0 ]; then
log_message "INFO" "10 / 2 = $result"
else
log_message "ERROR" "Division failed with code $exit_code"
fi
## Test with invalid values
echo ""
log_message "INFO" "Testing with invalid values"
divide 0 5
log_message "INFO" "Exit code: $?"
divide 10 0
log_message "INFO" "Exit code: $?"
divide abc 5
log_message "INFO" "Exit code: $?"
## Interactive mode
echo ""
log_message "INFO" "Interactive mode"
echo "Let's perform a division. Enter positive numbers."
## Get user input safely
num1=$(get_number "Enter first number")
num2=$(get_number "Enter second number")
## Perform division
result=$(divide "$num1" "$num2")
exit_code=$?
if [ $exit_code -eq 0 ]; then
log_message "INFO" "$num1 / $num2 = $result"
else
log_message "ERROR" "Division failed with code $exit_code"
fi
log_message "INFO" "Calculator finished"
Сохраните файл, сделайте его исполняемым и запустите скрипт:
chmod +x error_handling.sh
./error_handling.sh
Вы увидите вывод, похожий на следующий, и будете приглашены ввести числа:
[2023-11-04 13:45:23] [INFO] Starting division calculator
[2023-11-04 13:45:23] [INFO] 10 / 2 = 5.00
[2023-11-04 13:45:23] [INFO] Testing with invalid values
[2023-11-04 13:45:23] [ERROR] Numerator must be positive
[2023-11-04 13:45:23] [INFO] Exit code: 2
[2023-11-04 13:45:23] [ERROR] Division by zero is not allowed
[2023-11-04 13:45:23] [INFO] Exit code: 3
[2023-11-04 13:45:23] [ERROR] Numerator must be a number
[2023-11-04 13:45:23] [INFO] Exit code: 1
[2023-11-04 13:45:23] [INFO] Interactive mode
Let's perform a division. Enter positive numbers.
Enter first number:
Введите число, например 20
. Затем вас попросят ввести второе число:
Enter second number:
Введите еще одно число, например 4
, и вы должны увидеть:
[2023-11-04 13:45:30] [INFO] 20 / 4 = 5.00
[2023-11-04 13:45:30] [INFO] Calculator finished
Рекомендации по использованию функций в Bash
На основе наших примеров, вот несколько рекомендаций по использованию функций в Bash:
- Добавляйте описательные комментарии - Документируйте, что делает каждая функция, какие у нее параметры и возвращаемые значения.
- Используйте осмысленные имена функций - Выбирайте имена, которые ясно указывают на назначение функции.
- Проверяйте входные параметры - Проверяйте входные данные, чтобы предотвратить ошибки.
- Используйте локальные переменные - Предотвращайте конфликты имен переменных с помощью ключевого слова
local
.
- Возвращайте соответствующие коды завершения - Используйте стандартные коды возврата (0 для успешного выполнения, ненулевые значения для ошибок).
- Реализуйте правильную обработку ошибок - Логируйте ошибки и обрабатывайте их корректно.
- Сосредотачивайтесь на одной задаче в каждой функции - Каждая функция должна хорошо выполнять одну задачу.
- Используйте композицию функций - Создавайте сложную функциональность, комбинируя более простые функции.
- Документируйте возвращаемые значения - Ясно укажите, как возвращаются значения (через
echo
, код возврата и т.д.).
- Тестируйте крайние случаи - Убедитесь, что функции корректно обрабатывают необычные входные данные.
Следуя этим рекомендациям, вы можете создать более надежные, поддерживаемые и повторно используемые функции в Bash.
Создание библиотеки функций
В качестве последнего упражнения давайте создадим повторно используемую библиотеку функций:
touch math_functions.lib
Добавьте следующее содержимое:
#!/bin/bash
## math_functions.lib - A library of mathematical functions
## Add two numbers
add() {
echo $(($1 + $2))
}
## Subtract second number from first
subtract() {
echo $(($1 - $2))
}
## Multiply two numbers
multiply() {
echo $(($1 * $2))
}
## Divide first number by second (with decimal precision)
divide() {
if [ "$2" -eq 0 ]; then
return 1
fi
echo "scale=2; $1 / $2" | bc
return 0
}
## Calculate power: first number raised to second number
power() {
echo $(($1 ** $2))
}
## Check if a number is even
is_even() {
if (($1 % 2 == 0)); then
return 0
else
return 1
fi
}
## Check if a number is odd
is_odd() {
if is_even "$1"; then
return 1
else
return 0
fi
}
Теперь создайте скрипт, который использует эту библиотеку:
touch use_library.sh
Добавьте следующее содержимое:
#!/bin/bash
## Source the math functions library
source math_functions.lib
## Display a header
echo "Math Functions Demo"
echo "------------------"
## Test the functions
echo "Addition: 5 + 3 = $(add 5 3)"
echo "Subtraction: 10 - 4 = $(subtract 10 4)"
echo "Multiplication: 6 * 7 = $(multiply 6 7)"
## Test division with error handling
div_result=$(divide 20 5)
if [ $? -eq 0 ]; then
echo "Division: 20 / 5 = $div_result"
else
echo "Division error: Cannot divide by zero"
fi
## Test division by zero
div_result=$(divide 20 0)
if [ $? -eq 0 ]; then
echo "Division: 20 / 0 = $div_result"
else
echo "Division error: Cannot divide by zero"
fi
echo "Power: 2 ^ 8 = $(power 2 8)"
## Test the even/odd functions
echo ""
echo "Number properties:"
for num in 1 2 3 4 5; do
echo -n "Number $num is "
if is_even $num; then
echo "even"
else
echo "odd"
fi
done
Сохраните файл, сделайте его исполняемым и запустите скрипт:
chmod +x use_library.sh
./use_library.sh
Вы должны увидеть:
Math Functions Demo
------------------
Addition: 5 + 3 = 8
Subtraction: 10 - 4 = 6
Multiplication: 6 * 7 = 42
Division: 20 / 5 = 4.00
Division error: Cannot divide by zero
Power: 2 ^ 8 = 256
Number properties:
Number 1 is odd
Number 2 is even
Number 3 is odd
Number 4 is even
Number 5 is odd
Подход с использованием библиотеки демонстрирует, как можно создавать повторно используемые коллекции функций, которые можно импортировать в несколько скриптов, что способствует повторному использованию кода и его поддерживаемости.