bash shell 的返回值

Posted

技术标签:

【中文标题】bash shell 的返回值【英文标题】:return value of bash shell 【发布时间】:2019-09-16 18:23:57 【问题描述】:

我正在尝试学习 linux bash 脚本。我有一个脚本,我想获取这个脚本的返回值并将其存储在一个变量中。

欢迎任何帮助。

提前谢谢你。

#!/bin/bash
HOST_NAME=$1

 echo "105" ; sleep 5;  | telnet $HOST_NAME 9761;

【问题讨论】:

Capturing exit status of a failed command in a shell script的可能重复 考虑使用 ssh(最好使用 public-key-auth)来执行远程命令。首先也是最重要的:不使用明文密码。其次,由于 telnet 定期执行的任何交互式欢迎或每日消息通知,管理起来更容易。第三,容易(呃)执行完整的脚本。 【参考方案1】:

这取决于你所说的返回值是什么意思。

进程(在类 UNIX 系统上)可以将单个无符号字节作为退出状态返回给 shell,因此它会给出 0-255 范围内的值。按照惯例,零表示成功,任何其他值表示失败。

(在 C 等低级语言中,您可以获得的不仅仅是此退出状态,但这在 bash 中不可见)。

最后一个命令运行的退出状态存储在变量?中,因此您可以从$?中获取它的值,但是由于许多程序只返回0(有效)或1(无效) ),这没什么用。

Bash 条件,如 ifwhile 测试成功(退出代码为 0)或失败(退出代码为非零):

if some-command
then
    echo "It worked"
else
    echo "It didn't work"
fi

但是....

如果您的意思是要从脚本中获取 输出,那是另一回事。您可以使用以下方法捕获它:

var=$(some-command)

但是等等,它只捕获正常输出,路由到名为stdout(文件描述符1)的流,它不会捕获大多数程序写入名为stderr(文件描述符2)的流的错误消息。要捕获错误,您还需要将文件描述符 2 重定向到文件描述符 1:

var=$(some-command 2>&1)

输出文本现在位于变量 var 中。

【讨论】:

嗨 cDarke,感谢您提供的信息。【参考方案2】:

为避免混淆,不要将其视为/谈论它作为返回值,将其视为它的本质 - 退出状态。

在大多数编程语言中,您可以通过捕获函数在变量中返回的任何内容来捕获函数的返回值,例如使用类 C 语言:

int foo() 
    printf("35\n");
    return 7;


void main() 
    int var;
    var=foo();

在调用foo() 之后,main() 中的变量var 将保持值735 将被打印到标准输出。但是在 shell 中,代码看起来相似:

foo() 
    printf "35\n"
    return 7


main() 
    local var
    var=$(foo)

var 的值为35,而未提及的内置变量$? 始终保持上次命令运行的退出状态 的值为7。如果你想复制 35 到 stdout 并且 var 包含 7 的 C 行为,那就是:

foo() 
    printf "35\n"
    return 7


main() 
    local var
    foo
    var=$?

如果您习惯于其他基于 Algol 的语言(如 C),shell 函数使用关键字 return 报告其退出状态的事实一开始会令人困惑,但如果他们使用 exit,那么它将终止整个过程,所以他们不得不使用一些东西,很快就会明白它的真正含义。

因此,在讨论 shell 脚本和函数时,请使用“输出”和“退出状态”这两个词,而不是“返回”,有些人在某些情况下会认为这意味着这两种情况中的任何一种,这样可以避免所有混淆。

顺便说一句,为了避免让事情变得更加复杂,我在上面说过$? 是一个变量,但它实际上是“特殊参数”? 的值。如果您现在真的想了解区别,请参阅 https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameters 以讨论 shell 参数,其中包括 ?# 等“特殊参数”,12 等“位置参数”,以及我上面的脚本中使用的“变量”,例如 HOMEvar

【讨论】:

好答案。可能还值得一提的是,退出状态的数据类型仅限于无符号字符,这与函数可以返回任何数据类型的其他编程语言不同 @hek2mgl:这还不是全部。如果状态是 C 中的低 8 位,则 wait(3)waitpid(3) 的返回值是 pid_t 类型(通常是 unsigned int,但取决于实现)。 嗨,埃德,非常感谢【参考方案3】:

? 变量始终存储上一个命令的退出代码。

您可以使用$? 检索该值。

一些上下文:http://tldp.org/LDP/abs/html/exit-status.html

【讨论】:

【参考方案4】:

$? shell 变量存储返回值,但是对于 Linux telnet 客户端,这可能没有您想象的那么有用。如果远程主机关闭连接(或发生任何远程或网络错误),客户端将返回1,如果本地客户端成功关闭连接,则返回0。问题是编写了许多服务,以便它们发送数据然后自己关闭 TCP 连接,而无需等待客户端:

$ telnet time-b.timefreq.bldrdoc.gov 13
Trying 132.163.96.2...
Connected to time-b-b.nist.gov.
Escape character is '^]'.

58600 19-04-27 13:56:16 50 0 0 736.0 UTC(NIST) *
Connection closed by foreign host.
$ echo $?
1

即使客户端通过 TCP 流向服务器发送命令退出,这仍然会导致远程端关闭连接,结果相同:

$ telnet mail.tardis.ed.ac.uk 25
Trying 193.62.81.50...
Connected to isolus.tardis.ed.ac.uk.
Escape character is '^]'.
220 isolus.tardis.ed.ac.uk ESMTP Postfix (Debian/GNU)
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
$ echo $?
1

所以,无论如何,你都会得到1。如果您想要远程脚本的返回值,使用ssh 会更容易,如下所示:

$ ssh ssh.tardis.ed.ac.uk "exit 5"
THE TARDIS PROJECT  |  pubpubpubpubpubpubpubpubpub  |  Authorised access only
$ echo $?
5

据我所知,telnet 唯一会返回零(即成功)的情况是,如果您逃脱并且相当客户端,就像这样:

$ telnet www.google.com 80
Trying 216.58.210.36...
Connected to www.google.com.
Escape character is '^]'.
^]

telnet> quit
Connection closed.
$ echo $?
0

希望这会有所帮助。

【讨论】:

"$?shell 变量" 我知道这很挑剔,但$? 不是变量的名称,它是值 i> 变量?$ 前缀是一个给出值的一元运算符,我相信你知道。对不起。 我在不同的文档中看到过$VARVAR,我认为这取决于读者应该具备什么样的shell 编程专业知识... 我也看到它在其他地方被错误地命名。在使用export(这是一个非常基本的命令)和declare 等命令时会导致混淆,其中使用了变量名称,而不是前缀$。我发现对于初学者来说,最好是正确地知道哪个是名称以及 $ 到底是什么,否则你以后会遇到问题。

以上是关于bash shell 的返回值的主要内容,如果未能解决你的问题,请参考以下文章

在shell脚本中使用函数的返回值

bash shell如何获取到命令执行结果的值?

shell返回值不对,shell报错: numeric argument required?

shell返回值不对,shell报错: numeric argument required?

shell返回值不对,shell报错: numeric argument required?

在 shell 脚本中返回多个值的习惯用法