Shell 检测脚本是否来源于“/bin/sh”
我在这里找到的大多数答案似乎只适用于/bin/bash 像$BASH_SOURCE和$SHLVL这样的技巧似乎对sh不起作用 有一个答案要求使用return,因为它只在函数和源代码脚本中工作,并查看它是否生成任何错误,但我不明白为什么在命令行上执行return时,我从shell中注销了。如果我执行或获取了包含return的脚本,它就会退出该脚本。这是在我使用freebsd时发生的。我也不使用任何桌面环境 只需在命令行上键入Shell 检测脚本是否来源于“/bin/sh”,shell,sh,freebsd,Shell,Sh,Freebsd,我在这里找到的大多数答案似乎只适用于/bin/bash 像$BASH_SOURCE和$SHLVL这样的技巧似乎对sh不起作用 有一个答案要求使用return,因为它只在函数和源代码脚本中工作,并查看它是否生成任何错误,但我不明白为什么在命令行上执行return时,我从shell中注销了。如果我执行或获取了包含return的脚本,它就会退出该脚本。这是在我使用freebsd时发生的。我也不使用任何桌面环境 只需在命令行上键入 return 结果:注销 执行或寻源包含返回的脚本: 当我第一次在ma
return
结果:注销
执行或寻源包含返回的脚本:
当我第一次在macOSexecuted/bin/sh上执行相同操作时,情况并非如此。它在那里工作得非常好。上面说
sh:return:只能从函数或源脚本“返回”
正如所料
我正在寻找一种解决方案来检测脚本是否源于/bin/sh
我使用的是freebsd,目前我的默认shell设置为sh。我知道我可以安装bash,但我仍然想知道如何对/bin/sh执行相同的操作
更新:
我想再提一点细节
马科斯
在macOS中,我尝试通过命令行启动/bin/sh,后来我意识到它是一个非登录shell。所以,当我在那里输入注销时,reusult是:
sh:注销:非登录shell:使用“退出”
因此,我将/bin/sh作为默认shell,并且我确信/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是非登录shell,并且只是退出该shell,则不会显示任何输出
@user1934428在@CharlesDuffy的回答中提供了大量的信息。值得一读
在那个里,他提到FreeBSD手册并没有返回语句的文档。
我检查了OpenBSD对手册页的大小写是否相同,但它确实将return定义为:
返回[n]退出当前函数或。退出状态为n的脚本,或执行的最后一个命令的脚本
另一个问题是,大多数手册页都会显示bash手册中关于询问mansh.Idk是否应该这样的问题
另外,有人能建议我是否应该针对未定义的回报行为开始一个新问题吗?因为我觉得这个问题太离题了。不确定这样做是否是个好主意。$sh./detect-sourcing.sh
我们被处决了
$sh-c'/检测来源。sh'
我们被找到了
我还没有分析POSIX sh标准是否严格要求这一点,但它与MacOS上的/bin/sh(OP)配合使用。我从中找到了答案 缺少返回条目的手册页是错误的手册页 从正确的角度来看,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:
并将其与名称匹配。如果扩展生成了其他内容,则意味着脚本已经获得了源代码。另一种情况可能是用户将其重命名。所以它不太容易出错,但仍然应该完成我的工作。如果您计划使用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外壳的工作原理如手册第sh1页所述。
在MacOS中,虽然文件/bin/sh和/bin/bash略有不同,但/bin/sh基本上是bash。
请注意,Mac上的comand man sh为bash带来了手册页这个答案如何:?@Moby04,阅读该答案中的注释。还有来自@mklement0的更详细的答案呢?如果您从终端cmd行获取脚本,而不包括执行的return调用,它将在任何shell中注销您。我几乎可以肯定。这与从cmd行或cron或???运行脚本不同,它源于返回的脚本。这将返回cmd行。祝你好运。@user1934428 bash在任何系统上都是从GNU源代码构建的,但BSD和Linuxes有一个单独的sh手册页。POSIX中的结果未指明:如果我的问题不清楚,我道歉,我会在拿到笔记本后立即编辑它。我的平台是freebsd,在这里它显示了意外的结果。我在macOS上也做了同样的测试,一切正常。明白了。不幸的是,我不知道POSIX标准要求任何地方存在可检测的行为差异,因此除非其他人能够找到这一点,否则我们将
需要重新调谐以发现FreeBSD的实现与苹果的实现之间的差异。这仍然是为什么在交互式shell中返回终止它的原因。有趣的是,这个函数甚至没有提到return语句,例如ash的手册页,它应该非常接近sh,加上只在函数内部定义return的效果,所以它在函数外部的作用似乎是未指定的行为。有些离题,但是可能很有趣:zsh定义了返回的效果,至少对于它在trap语句中的使用也是如此,但是对于它在交互提示中的使用也是沉默的。尝试一下,对于我的zsh 5.5.1,返回不会终止当前shell。bash也不会让我退出,而ash和dash会。对我来说,看起来有点过分了。如果脚本是使用完整路径执行的,为什么要删除路径名?我认为这不管用。假设脚本t1源于另一个脚本t2。在t2中检查$0将反映t1是如何被调用的,因为在t2运行时它没有被更改。@jhnc,我的错,我太懒了,没有在邮件列表中写出完整的解释。我更新了我的答案。这是因为,如果一个脚本知道它被调用什么,我们将它的名称与${0*/}匹配,但它不匹配,这就意味着该脚本已经获得了源代码。Ofc这并不是万无一失的,但与其他方法相比,这种方法失败的情况似乎要少一些。@YuriGinsburg,我们无法知道脚本是从什么路径执行的。但脚本名称更改的情况仍然较少。因此,如果脚本名和${0*/}不匹配,则表示它已被源代码化。如上所述,它不是完全无错误的,但仍然有较少的机会导致错误。@Mihir源代码的脚本在$0和${0*/}中只有sh,我们将结果与此进行比较。但是对于已执行的脚本,比如/home/user/bin/sh,$0将生成完整路径,${0*/}just sh–与源代码脚本相同。我认为如果从另一个脚本t2内部调用t,这不起作用$0保留t2中的值,并将反映t2是如何被调用的。@jhnc是正确的,但macos上的yea man sh生成man bash
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.
${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