1 需求
在/etc/rc.local
中编写并执行函数,使其实现下列功能:
- 每次开机时,如果检测到Transmission要使用的指定硬盘分区,则将其挂载到指定目录,否则无操作。
这一点有点像Windows分配盘符的机制,操作系统事先不会通过/etc/fstab
强制要求某个分区必须存在,对移动硬盘、热插拔硬盘位、NAS、SAN等使用模式更加友好。 - 如果上一步检测到分区并挂载成功,则
sleep
一段时间后启动Transmission。 - 如果检测到分区但挂载失败,则记录
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间切换。
-e
在dash
中的含义是:
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
的含义相似,但不完全相同。
-e
在dash
中的执行效果如下:
[root@localhost ~]# echo $$
8269
[root@localhost ~]# dash -e
# echo $$
11142
# false
[root@localhost ~]# echo $$
8269
-e
在bash
中的执行效果是一样的:
[root@localhost ~]# echo $$
8269
[root@localhost ~]# bash -e
[root@localhost ~]# echo $$
11157
[root@localhost ~]# false
[root@localhost ~]# echo $$
8269