在Ubuntu /etc/rc.local中处理非零返回值

1 需求

/etc/rc.local中编写并执行函数,使其实现下列功能:

  1. 每次开机时,如果检测到Transmission要使用的指定硬盘分区,则将其挂载到指定目录,否则无操作。
    这一点有点像Windows分配盘符的机制,操作系统事先不会通过/etc/fstab强制要求某个分区必须存在,对移动硬盘、热插拔硬盘位、NAS、SAN等使用模式更加友好。
  2. 如果上一步检测到分区并挂载成功,则sleep一段时间后启动Transmission。
  3. 如果检测到分区但挂载失败,则记录mount命令的返回值并输出。

2 尝试实现

实现前两项功能的函数代码很简单,没什么坑,如下所示:

selective_start_transmission(){
    if [ -b "$TRANSMISSION_SCRATCH_DRIVE_LINK" -a -d "$TRANSMISSION_SCRATCH_DRIVE_MOUNTPOINT" ]; then
        mount "$TRANSMISSION_SCRATCH_DRIVE_LINK" "$TRANSMISSION_SCRATCH_DRIVE_MOUNTPOINT"
        ERRLVL=$?
        if [ "x0" = "x"${ERRLVL} ]; then
            echo "mount: success"
            sleep 5
            if [ -d "$TRANSMISSION_SCRATCH_DIR" ]; then
                systemctl start transmission-daemon
            fi
        else
            echo "mount: error level $ERRLVL"
        fi
    fi
}

然而在处理mount命令的返回值(代码中将其保存到$ERRLVL)时遇到了坑。mount命令返回非零值时,脚本直接退出,第二个if代码块以及后面的脚本都执行不到。

[root@localhost ~]# /etc/rc.local selective_start_transmission
mount: /dev/sdj1 is already mounted or /mnt/WD30EZRX-00 busy
       /dev/sdj1 is already mounted on /mnt/WD30EZRX-00
[root@localhost ~]# echo $?
32

(函数中的两个echo都没有执行)

3 解决方法

如果只是想处理错误的话,把mount写到第二个if [ ]里面就可以,但是这样就拿不到返回值了。
先后查了Bash中try-catch的实现、括号的用法、$-的含义和set命令等资料,没有任何头绪。

于是用了一个比较丑陋的方法解决,也就是mount后面直接跟着ERRLVL=$?,而且无论成功失败都会执行。

    if [ -b "$TRANSMISSION_SCRATCH_DRIVE_LINK" -a -d "$TRANSMISSION_SCRATCH_DRIVE_MOUNTPOINT" ]; then
        ERRLVL='"unset"'
        mount "$TRANSMISSION_SCRATCH_DRIVE_LINK" "$TRANSMISSION_SCRATCH_DRIVE_MOUNTPOINT" && ERRLVL=$? || ERRLVL=$?
        if [ "x0" = "x"${ERRLVL} ]; then
            ......

4 兔子洞大冒险

随后我在这里看到了
#!/bin/bash -x
这种写法,于是看了一眼/etc/rc.local的第一行:

#!/bin/sh -e

我想知道这里的-e是什么意思,于是随手man sh了一下,然后才注意到这里的sh默认是dash,不过也可以在bash和dash间切换。
-edash中的含义是:

   Argument List Processing
     All of the single letter options that have a corresponding name can be
     used as an argument to the -o option.  The set -o name is provided next
     to the single letter option in the description below.  Specifying a dash
     “-” turns the option on, while using a plus “+” disables the option.  The
     following options can be set from the command line or with the set
     builtin (described later).
     ...
           -e errexit       If not interactive, exit immediately if any
                            untested command fails.  The exit status of a com‐
                            mand is considered to be explicitly tested if the
                            command is used to control an if, elif, while, or
                            until; or if the command is the left hand operand
                            of an “&&” or “||” operator.

也就是说要try的命令必须立即test,或者放到&&或者||操作符的左侧,否则一旦命令失败,dash会立即终止脚本的运行。这一点和set -e的含义相似,但不完全相同。
-edash中的执行效果如下:

[root@localhost ~]# echo $$
8269
[root@localhost ~]# dash -e
# echo $$
11142
# false
[root@localhost ~]# echo $$
8269

-ebash中的执行效果是一样的:

[root@localhost ~]# echo $$
8269
[root@localhost ~]# bash -e
[root@localhost ~]# echo $$
11157
[root@localhost ~]# false
[root@localhost ~]# echo $$
8269

你可能感兴趣的:(在Ubuntu /etc/rc.local中处理非零返回值)