我正在尝试编写一个脚本来检测 Linux 操作系统和版本,并通过使用条件和运算符根据结果执行不同的命令。
检测操作系统
if [ -f /etc/os-release ]; then
. /etc/os-release
OS="$NAME"
OS_version="$VERSION_ID"
elif [ -f /etc/debian_version ]; then
# Older Debian/Ubuntu/etc.
OS="Debian"
OS_version="$(cat /etc/debian_version)"
fi
如果我回显这些变量,它们会返回
$ echo $OS
Debian GNU/Linux
$ echo $OS_version
10
在下面的示例中我想匹配德班和操作系统版本10。但是,那$操作系统变量不仅仅包含单词德班所以我需要某种通配符,这样我就可以进行部分匹配。
我发现通过命令替换来使其工作的唯一方法是回显$操作系统变量到 stdout 并将其输送到 grep 命令中,然后执行通配符搜索。这是我最后想出的 if 语句:
if [ "$(echo "$OS" | grep 'Debian*')" -a "$OS_version" -ge 10 ]; then
echo "OS is Debian"
sleep 4
else
echo "OS is other"
sleep 4
fi
由于我将在其他基于 Unix 的操作系统上使用此脚本,因此我希望使此脚本尽可能广泛兼容并遵守 POSIX 标准。
在 Ubuntu 21.04 上测试我的脚本时,我发现当涉及小数位时,Linux 很难计算出哪个数字大于另一个数字。下面我创建了两个 shell 脚本,它们导出一个带有两位小数的两个整数,并使用 if 语句检查它是否大于和/或等于另一个数字。
20.10.sh
#!/bin/sh
export OS_version="20.10"
if [ "$OS_version" -ge 21.04 ]; then
echo "Your OS is new enough"
sleep 2
else
echo "Your OS is too old!"
sleep 2
fi
20.10.sh输出
~$ ./20.10.sh
YOUR OS VERSION IS >> 20.10
./20.10.sh: 6: [: Illegal number: 20.10
Your OS is too old!
23.45.sh
#!/bin/sh
export OS_version="23.45"
if [ "$OS_version" -ge 21.04 ]; then
echo "Your OS is new enough"
sleep 2
else
echo "Your OS is too old!"
sleep 2
fi
23.45.sh输出
~$ ./23.45.sh
YOUR OS VERSION IS >> 23.45
./23.45.sh: 6: [: Illegal number: 23.45
Your OS is too old!
这23.45.sh脚本应该回显“您的操作系统足够新”,但没有回显并显示非法号码的错误。
有没有办法检测带小数位的不同数字的大小?
答案1
标准[
命令仅支持十进制整数作为其数字比较运算符。某些[
实现(例如[
内置的)ksh93
确实支持浮点数以及扩展,但这不可移植,并且无论如何浮点数比较与版本比较不同。
例如10.2
,浮点数大于10.10
,但当它们被解释为版本时则相反。
Ubuntu 版本是日期。 20.04(2020年4月)是在20.10(2010年10月)之前。对于这些,您可以使用词法比较(可以使用 进行awk
),前提是您不要追溯到 9.10 (Karmic Koala) 或更早版本,并且不包括次要数字(如 18.04.4 中)(或者如果它确实永远不会达到 10)。
1.2pre5-beta1.2
小于1.2
while1.2a
通常被认为大于1.2
。如果不知道版本命名约定,通常很难比较版本。
在 GNU 系统上,您可能希望遵循 GNUsort
的--version-sort
算法。
version_greater_than() {
local before_sort="$1"$'\n'"$2"
[ "$before_sort" != "$(printf %s "$before_sort" | sort --stable --version-sort)" ]
}
(在 ksh93/zsh/bash 语法中)或其sh
等效语法:
version_greater_than() {
[ "$1
$2" != "$(printf '%s\n' "$1" "$2" | sort --stable --version-sort)" ]
}
然后,你可以这样做:
if version_greater_than 10.10 10.4; then
echo 10.10 greater than 10.4
fi
POSIXly,您可以采取一种awk
方法,将所有数字序列用零填充到任意长度,并在 C 语言环境中进行词法比较:
compare_versions() {
LC_ALL=C awk -- '
function pad(v, ret) {
while (match(v, /[0-9]+/)) {
ret = ret substr(v, 1, RSTART - 1) \
sprintf("%09d", substr(v, RSTART, RLENGTH))
v = substr(v, RSTART + RLENGTH)
}
return ret v
}
BEGIN {exit !(pad(ARGV[1]) '"$2"' pad(ARGV[2]))}' "$1" "$3"
}
用作:
if compare_versions 1.10 '>' 1.2; then
echo '1.10 > 1.2'
fi
答案2
您不能使用 或 等运算符-lt
进行-ge
定点或浮点比较;它们是严格的整数数学运算符。 bash
(例如)不知道如何做非整数数学。您必须使用 eg<
或 来将版本号作为字符串进行比较>=
,同时还要注意 eg1.1
是“大于” 1.10
。您可以通过构建sort -v
逻辑来解决这个问题。
答案3
只要版本号是浮点数(而不是像 20.04.3 这样的东西),您就可以将比较通过管道传输到bc
.
例如,更改此:
if [ "$OS_version" -ge 21.04 ]; then
对此:
if [ $(echo "$OS_version >= 21.04" | bc) ]; then