shell 检测系统包的脚本出错

Error in shell script for detecting packages on system

我写了一个 shell 脚本来检测是否安装了一个包。如果已安装,我的脚本应该写下它的名称和状态。我无法找出我的代码有任何问题,但是当我 运行 它时,它不会在 if [ $? == 0 ] 条件下执行命令。

#!/bin/bash

if [ "" == "" ]; then
    echo "Please hold the line."
else
    dpkg -s $@ &> /dev/null
fi

if [ $? == 1 ]; then
    echo -e "Package 3[0;31mNOT3[0m found." >&2
else
    if [ $? == 0 ]; then
        for i in $@; do
            dpkg -s $i | grep Package
            dpkg -s $i | grep Status
        done
    fi
fi

但对我来说最奇怪的是,如果我在 if 语句后添加一个 echo,它就可以工作。看起来是这样的:

#!/bin/bash

if [ "" == "" ]; then
    echo "Please hold the line."
else
    dpkg -s $@ &> /dev/null
fi

if [ $? == 1 ]; then
    echo -e "Package 3[0;31mNOT3[0m found." >&2
else
    echo hi
    if [ $? == 0 ]; then
        for i in $@; do
            dpkg -s $i | grep Package
            dpkg -s $i | grep Status
        done
    fi
fi

因此,如果我将 echo -n 添加到代码中的正确位置,它将按我的意愿工作。但我只想知道第一个有什么问题?

$?是上次执行命令的return状态。 0 是成功的,1 或其他任何东西都是错误的。注:

dpkg -s python &> /dev/null # returns 0 (OK, true) 
# $? equals 0 now

[ #? == 1 ] # false         # returns 1 (error) 
# $? equals 1 now

[ #? == 0 ] # false         # returns 1 (error)

当你输入 echo 时,它起作用了:

dpkg -s python &> /dev/null # returns 0 (OK, true) 
# $? equals 0 now

[ #? == 1 ] # false         # returns 1 (error) 
# $? equals 1 now

echo hi                     # returns 0 (OK) 
# $? equals 0 now

[ #? == 0 ] # true          # returns 0 (OK)

您可以将 $? 保存到一个变量中,但是您实际上并不需要 else 中的 if ,因为您已经检查了 if #? == 1 所以只需将您的代码放在 else 中:

#!/bin/bash

if [ "" == "" ]; then
    echo "Please hold the line."
else
    dpkg -s $@ &> /dev/null
fi

if [ $? == 1 ]; then
    echo -e "Package 3[0;31mNOT3[0m found." >&2
else
    for i in $@; do
        dpkg -s $i | grep Package
        dpkg -s $i | grep Status
    done
fi

如果您担心 $? 的其他可能 return 状态(大于一个)。您可以将脚本重写为

#!/bin/bash

if [ "" == "" ]; then
    echo "Please hold the line."
else
    dpkg -s $@ &> /dev/null
fi

if [ $? == 0 ]; then
    for i in $@; do
        dpkg -s $i | grep Package
        dpkg -s $i | grep Status
    done
else
    echo -e "Package 3[0;31mNOT3[0m found." >&2
fi

我认为一般来说,您可以更加慎重地考虑您的 return 代码处理。您正在假设 $? 所指的内容可能无效,具体取决于您的程序流程,并且无论如何,都会使程序更难阅读和理解。

#!/bin/bash

dpkg -s $@ &> /dev/null
installed=$?

if [ $installed -eq 0 ]; then
    for i in $@; do
        dpkg -s $i | grep Package
        dpkg -s $i | grep Status
    done
else
    echo -e "Package 3[0;31mNOT3[0m found." >&2
fi