使用 mount 的输出作为变量的 Bash 脚本会引发大量错误

Dav*_*ble 4 command-line bash scripts

Ubuntu 18.04 服务器 + LXDE。我无法掌握这个 bash 脚本的窍门。
这是我的脚本“开始”(带有行号):

#!/bin/bash
reply=sudo mount 192.168.0.2:/home/dk/NFS /home/dk/NFS
if $reply == 0
then 
    echo "NFS mounted OK"
else 
    echo "Mounting NFS failed: $reply"
fi

reply=sudo mount LABEL="60GB" /home/dk/60GB
if $reply == 0
then 
    echo "60GB mounted OK"
else 
    echo "Mounting 60GB failed: $reply"
fi
exit 0
Run Code Online (Sandbox Code Playgroud)

这是运行它的结果:

$ ./scripts/start
mount: only root can do that
./start: line 3: ==: command not found
Mounting NFS failed: 
mount: only root can do that
./start: line 11: ==: command not found
Mounting 60GB failed: 
$ 
Run Code Online (Sandbox Code Playgroud)
  • 为什么它忽略了sudo之前mount
  • 为什么不认为if是命令?
  • 为什么不打印 的(非零)值$reply

Ser*_*nyy 11

好吧,您错误地分配了命令的输出。应该:

reply=$(sudo mount 192.168.0.2:/home/dk/NFS /home/dk/NFS)
Run Code Online (Sandbox Code Playgroud)

这称为命令替换。有时您会在旧的 Bourne shell 语法中看到它使用反引号而不是$(...),但现在不推荐这样做,因为反引号不能轻松嵌套,而您可以嵌套$( cmd1 $(cmd2))

为什么它不认为“如果”是一个命令?

If 语句对命令进行操作,但您提供的是 variable $reply,它仅暂时存在(请参阅后面的答案),因此它仅存在于mount命令的环境中,但运行脚本的 shell 对此一无所知 - 它不存在. 要比较字符串,请使用[, 是的,它是一个命令,也称为test. 也一样

if test "$reply" == 0
Run Code Online (Sandbox Code Playgroud)

看到报价了吗?这很重要,否则如果有空格,shell 会将变量扩展为两个或多个单独的实体,而不是一个。

但是如果你想检查命令的退出状态,就做

if mount 192.168.0.2:/home/dk/NFS /home/dk/NFS
Run Code Online (Sandbox Code Playgroud)

看没有sudo?那是因为在脚本中多次使用 sudo 通常是多余的。只需使用 sudo 调用脚本本身,所有命令都将具有 root 权限。

我还想说 echo 是多余的,因为 mount 命令已经可以将错误打印到终端,但是如果你想要自定义消息,你可以这样做

if mount 192.168.0.2:/home/dk/NFS /home/dk/NFS 1> /dev/null
then
       echo "Success"
else
       echo "Fail"
fi
Run Code Online (Sandbox Code Playgroud)

由于1>正常输出被抑制(实际上重定向到/dev/null特别是为此目的)但如果出现任何问题,则会显示错误。

为什么它在“mount”之前忽略了“sudo”?

至于为什么会收到错误消息,那是因为表单

reply=sudo mount 192.168.0.2:/home/dk/NFS /home/dk/NFS
Run Code Online (Sandbox Code Playgroud)

被视为envvariable=value command arg1 arg2,即您将result带值的变量sudo放入mount命令环境中。命令会知道它,但在命令退出后 - 变量也消失了。

为什么不打印 $reply 的(非零)值?

因为reply不像之前解释的那样存储退出状态。实际上,shell 已经提供了一个变量,$?因此将其用作

if [ $? -eq 0 ] 
Run Code Online (Sandbox Code Playgroud)

冲洗并重复脚本中其他语句的建议。

祝你好运

  • @DaveKimble 是的,习惯 shell 脚本中的语法需要时间。但最终你会通过足够的练习和阅读这里和 unix.stackexchange.com 或 stackoverflow 上的答案来获得它。你可以随时尝试 Python。那里的语法更好更快,但您必须通过“Popen”模块调用诸如“mount”之类的外部命令。顺便说一句,如果答案解决了问题,请不要忘记将其标记为已接受(灰色复选标记)。或者不做标记。这不是要求。 (2认同)

Xen*_*050 8

除了 Sergiy 的好答案之外,您还可以考虑使用 AND 和 OR 列表来快速检查命令是否返回零(成功)退出状态,例如

command && echo "command succeeded" || echo "command failed"
Run Code Online (Sandbox Code Playgroud)

这是摘录自man bash

AND 和 OR 列表分别是由&&||控制运算符分隔的一个或多个管道的序列。AND 和 OR 列表以左结合性执行。AND 列表具有以下形式

      command1 && command2
Run Code Online (Sandbox Code Playgroud)

当且仅当 command1 返回退出状态为零时才执行 command2。

OR 列表具有以下形式

      command1 || command2
Run Code Online (Sandbox Code Playgroud)

当且仅当 command1 返回非零退出状态时才执行 command2。AND 和 OR 列表的返回状态是列表中执行的最后一个命令的退出状态。

您可以将它们组合起来,如果需要,还可以查看退出状态,例如:

sudo mount 192.168.0.2:/home/dk/NFS /home/dk/NFS && \
echo "NFS mounted OK" || echo "Mounting NFS failed: $?"
Run Code Online (Sandbox Code Playgroud)