In spite of all the POSIX shell disadvantages, I am still sticking with it and I love its portability.
Recently, I was searching for a way of code re-use, which turns out to be structured programming and input validation = Yes, in a POSIX shell script.
Let me begin with the simpler.
is_integer()
+ is_exit_code()
is_integer ()
{
case "${1#[+-]}" in
(*[!0123456789]*) return 1 ;;
('') return 1 ;;
(*) return 0 ;;
esac
}
is_exit_code ()
{
is_integer "1ドル" &&
case "1ドル" in
([+-]*) return 1 ;;
esac &&
[ "1ドル" -le 255 ]
}
Here, I continue on with further chained functions.
print_error()
+ print_error__exit()
print_error ()
{
if ! { [ $# -eq 2 ] && [ -n "1ドル" ] && [ -n "2ドル" ]; } then
printf '%b\n' "Some longer error message."
exit 1
fi
printf '%b\n' \
"${color_red}Error occurred$tput_reset" \
"Error heading: $color_yellow1ドル$tput_reset" \
"Error message: 2ドル"
} >&2
print_error__exit ()
{
if ! { [ $# -eq 2 ] && [ -n "1ドル" ] && [ -n "2ドル" ]; } &&
! { [ $# -eq 3 ] && [ -n "1ドル" ] && [ -n "2ドル" ] && is_exit_code "3ドル" && [ "3ドル" -ge 1 ]; } then
printf '%b\n' "Some longer error message."
exit 1
fi
print_error "1ドル" "2ドル"
exit "${3:-1}"
} >&2
So, in this bare example, the chains go up like this:
print_error__exit ()
🠆print_error ()
;print_error__exit ()
🠆is_exit_code ()
🠆is_integer ()
.
Despite I am quite confident, these examples work as they should, one never knows, a maybe different point of view would shed a different light on my process.
2 Answers 2
Your code looks nice. I give some additional advice.
- You can debug by calling the
source
command in your terminal (REPL). - You can divide the common codes and the main codes by writing the
source
in the main code. - Take care of an enormous number. The number
99999999999999999999999999999999999999999999999999
, and so on. - The action of writing some function is not functional programming but structured programming. The functional programming paradigm is like the idea of stream and pipe. Then, if you do not know functional programming, you may practice functional programming.
In spite of all the POSIX shell disadvantages, I am still sticking with it and I love its portability.
You will come to realize that adhering to POSIX for your shell scripts is more often an advantage than a disadvantage. The reason the UNIX shells and utilities are powerful is because they standardized on the pipeline API and generally followed some vague conventions regarding exit status and commandline options. What the other UNIX shells added on top of the POSIX shell baseline are either anti-features or inconsequential enough to not be worth sacrificing portability for. Remember that Perl is a natural extension of the UNIX shells, so what most of these shell extensions achieve is nothing but an inferior Perl. The traditional UNIX shells are a dead end and should be considered to be on eternal life support.
PowerShell improved on the traditional UNIX shells by also standardizing on the commandline options and input and output format, bringing structure to the arbitrary text passed around in the UNIX shells. In theory and based on technical merits alone, PowerShell should be the next in line in the evolution of UNIX shells, but as it failed to successfully assimilate the strengths of the UNIX shells with its own strengths due to major design flaws and a spotty implementation, it is in fact a big step backward in some aspects.
It is a very good idea to do input validation. To see why, read Mr Chazelas's answer where he also provides an implementation of the is_integer
function.
Stéphane Chazelas is, amongst other specialties, a shell programming guru and the discoverer of the initial Shellshock vulnerabilities, so his code is often worth studying and copying (with proper attributions of course).
For your is_exit_code
function implementation, note that in the latest POSIX.1-2024, the shell exit status is permitted to be greater than 255 in certain circumstances:
- Otherwise, if the command terminated due to the receipt of a signal, the shell shall assign it an exit status greater than 128. The exit status shall identify, in an implementation-defined manner, which signal terminated the command. Note that shell implementations are permitted to assign an exit status greater than 255 if a command terminates due to a signal.
I think ksh is one such shell implementation that can return an exit status greater than 255, if you're curious.
By the way, it is better to quote the $#
variable since it can be more than a single digit and the IFS
can be set to a number.
One can rarely be too careful (though there are a few exceptions) when it comes to quoting in shell scripts.
Why does your print_error__exit
function have two underscores in the name?