检测脚本是否来自“ / bin / sh”

时间:2019-08-18 19:15:08

标签: shell sh freebsd

我在这里发现的最常见答案仅是/bin/bash

$BASH_SOURCE$SHLVL之类的技巧似乎不适用于sh

有一个要求使用return的答案,因为它仅在函数和源脚本中起作用,并查看它是否产生任何错误,但我不明白为什么在命令上执行return -line我退出了shell。如果我“执行或获取”包含return的脚本,它将退出该脚本。这是我在freebsd上时发生的。另外,我在那里不使用任何桌面环境。

只需在命令行上输入

return
  

结果:已注销

执行或获取包含return的脚本:

$ cat testscript
#! /bin/sh

echo hello
return
echo hello
$ ./testscript
hello
$ . testscript
hello
$ 

当我在macOS(首先执行/ bin / sh)上执行相同操作时,情况并非如此。在那里工作得很好。那里只是说

  

sh:return:只能从函数或源脚本中“返回”

与预期的一样。

我正在寻找一种解决方案,以检测在/bin/sh情况下脚本是否为源。

我正在使用freebsd,目前我的默认shell设置为sh。我知道我可以安装bash,但是我仍然想知道如何为/bin/sh做同样的事情。

更新:

我想提一点细节。

MacOS

macOS中,我尝试通过命令行启动/bin/sh,后来我意识到它是一个非登录shell。因此,当我在此处输入logout时,结果是:

  

sh:注销:不登录shell:使用`exit'

因此,我将/bin/sh设置为默认外壳程序,并且确信执行了/bin/sh。当我在此处输入return时,我得到的输出是:

  

sh:return:只能从函数或源脚本中“返回”

再次达到预期。但是当我输入echo $SHELL时,输出为:

  

/ bin / bash

然后我检查了机器的/bin目录,而/bin/sh/bin/bash似乎没有链接。

FreeBSD

现在我也尝试在那里执行/bin/sh。结果如下:

$ /bin/sh
$ return
$ return
logged out on 2nd return

因此,如果/bin/sh是非登录外壳程序,并且仅退出该外壳程序,那么用简单的语言就不会显示任何输出。

@ user1934428在@CharlesDuffy的答案中提供了很多信息。值得一读。

他提到FreeBSD手册中没有return声明的文档。 sh man page, FreeBSD

我检查了OpenBSD的手册页是否具有相同的大小写,但是确实将return定义为:

  

返回[n]退出当前功能或。退出状态为n或最后执行的命令的脚本。

sh man page, OpenBSD

另一个问题是,大多数手册页都在bash手册中显示有关man sh的要求。如果它应该是那样或否,则为Idk。

还可以有人建议我为return的不确定行为提出一个新问题吗?因为我认为这个问题已经脱离话题了。不确定这样做是否是个好主意。

3 个答案:

答案 0 :(得分:3)

$ sh ./detect-sourcing.sh
We were executed
$ sh -c '. ./detect-sourcing.sh'
We were sourced
#!/bin/sh
if (return 2>/dev/null); then
  echo "We were sourced"
else
  echo "We were executed"
fi

我还没有分析POSIX sh标准是否严格要求这样做,但是它可以在OS的stated platform的MacOS上与/bin/sh一起使用。

答案 1 :(得分:0)

我通过FreeBSD mailing lists找到了答案。

缺少return条目的手册页是错误的手册页。

看看正确的man page,已经说明了return语句的完整行为。

The syntax  of the return command is

       return [exitstatus]

     It terminates the current executional scope, returning from the closest
     nested function or sourced script; if no function or sourced script is
     being executed, it exits the shell instance.  The return command is im-
     plemented as a special built-in command.

如伊恩(Ian)在邮件列表中所建议的那样,对于/bin/sh,一种好方法似乎是为脚本保留一个固定名称并展开$0

${0##*/}

,然后将其与名称匹配。如果扩展产生了其他任何内容,则表示脚本已获得源。另一种情况是用户将其重命名。因此,它并非完全容易出错,但仍然应该完成我的工作。

答案 2 :(得分:0)

如果您打算使用Bourne shell(/ bin / sh),仅测试$ 0会很好。

$ cat t
#!/bin/sh

if [ $0 == "sh" ]; then
    echo "sourced"
else
    echo executed
fi

$ . t
sourced
$ . ./t
sourced
$ ./t
executed
$ sh t
executed
$ sh ./t
executed

如果要从其他shell调用或获取脚本,请针对shell名称列表测试$ 0。

正如@Mihir所指出的那样,FreeBSD shell的工作方式如手册页sh(1)中所述。 在MacOS中,/ bin / sh基本上是bash,尽管文件/ bin / sh和/ bin / bash略有不同。 请注意,在Mac上,comand man sh为bash带来了手册页