检测脚本是否来自“/bin/sh”
Detect if a script has been sourced in "/bin/sh"
我在这里找到的大多数答案似乎只适用于 /bin/bash
。
$BASH_SOURCE
和 $SHLVL
等技巧似乎不适用于 sh
。
有一个答案要求使用 return
,因为它只适用于函数和源脚本,看看它是否产生任何错误,但我不明白为什么执行 return
在命令行上,我退出了 shell。如果我“执行或获取”包含 return
的脚本,它只会退出该脚本。这是我在 freebsd
时发生的事情。我也不在那里使用任何桌面环境。
只需在命令行输入,
return
result: logged out
正在执行或获取包含 return
:
的脚本
$ cat testscript
#! /bin/sh
echo hello
return
echo hello
$ ./testscript
hello
$ . testscript
hello
$
当我在 macOS
上执行相同操作时情况并非如此(首先执行 /bin/sh)。它在那里工作得很好。那里只是说
sh: return: can only `return' from a function or sourced script
符合预期。
我正在寻找一种解决方案来检测脚本是否来自 /bin/sh
。
我正在使用 freebsd
,目前我将默认 shell 设置为 sh
。我知道我可以安装 bash
,但我仍然想知道如何为 /bin/sh
做同样的事情。
更新:
我想再说一点细节。
MacOS
在macOS
中我尝试通过命令行启动/bin/sh
,后来才知道是非登录shell。所以,当我在那里输入 logout
时,结果是:
sh: logout: not login shell: use `exit'
所以我将 /bin/sh
作为我的默认值 shell 并且我确信 /bin/sh
已被执行。当我在那里输入 return
时,我得到的输出是:
sh: return: can only `return' from a function or sourced script
果然不出所料。但是当我输入 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
手册没有 return
语句的文档。
sh man page, FreeBSD
我检查了 OpenBSD 是否有相同的手册页大小写,但它确实将 return
定义为:
return [n] Exit the current function or . script with exit status n, or that of the last command executed.
另一个问题是大多数手册页显示 bash
手册要求 man sh
。我不知道它是否应该是那样的。
此外,有人可以建议我是否应该针对 return
的未定义行为开始一个新问题吗?因为我觉得这个问题真的跑题了。不确定这样做是否是个好主意。
$ 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 标准的严格要求,但它适用于 MacOS 上的 /bin/sh
,OP 的 .
我通过 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
的情况下,一个好的可能方法似乎是为您的脚本保留一个固定名称并扩展 [=15=]
:
${0##*/}
并将其与名称匹配。如果扩展产生任何其他内容,则意味着脚本已被获取。另一种情况可能是用户重命名了它。所以它不是完全容易出错,但仍然应该完成我的工作。
如果您打算使用 Bourne shell (/bin/sh),只测试 $0 效果很好。
$ cat t
#!/bin/sh
if [ [=10=] == "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 上的命令 man sh 为 bash
带来手册页
我在这里找到的大多数答案似乎只适用于 /bin/bash
。
$BASH_SOURCE
和 $SHLVL
等技巧似乎不适用于 sh
。
有一个答案要求使用 return
,因为它只适用于函数和源脚本,看看它是否产生任何错误,但我不明白为什么执行 return
在命令行上,我退出了 shell。如果我“执行或获取”包含 return
的脚本,它只会退出该脚本。这是我在 freebsd
时发生的事情。我也不在那里使用任何桌面环境。
只需在命令行输入,
return
result: logged out
正在执行或获取包含 return
:
$ cat testscript
#! /bin/sh
echo hello
return
echo hello
$ ./testscript
hello
$ . testscript
hello
$
当我在 macOS
上执行相同操作时情况并非如此(首先执行 /bin/sh)。它在那里工作得很好。那里只是说
sh: return: can only `return' from a function or sourced script
符合预期。
我正在寻找一种解决方案来检测脚本是否来自 /bin/sh
。
我正在使用 freebsd
,目前我将默认 shell 设置为 sh
。我知道我可以安装 bash
,但我仍然想知道如何为 /bin/sh
做同样的事情。
更新:
我想再说一点细节。
MacOS
在macOS
中我尝试通过命令行启动/bin/sh
,后来才知道是非登录shell。所以,当我在那里输入 logout
时,结果是:
sh: logout: not login shell: use `exit'
所以我将 /bin/sh
作为我的默认值 shell 并且我确信 /bin/sh
已被执行。当我在那里输入 return
时,我得到的输出是:
sh: return: can only `return' from a function or sourced script
果然不出所料。但是当我输入 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
手册没有 return
语句的文档。
sh man page, FreeBSD
我检查了 OpenBSD 是否有相同的手册页大小写,但它确实将 return
定义为:
return [n] Exit the current function or . script with exit status n, or that of the last command executed.
另一个问题是大多数手册页显示 bash
手册要求 man sh
。我不知道它是否应该是那样的。
此外,有人可以建议我是否应该针对 return
的未定义行为开始一个新问题吗?因为我觉得这个问题真的跑题了。不确定这样做是否是个好主意。
$ 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 标准的严格要求,但它适用于 MacOS 上的 /bin/sh
,OP 的
我通过 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
的情况下,一个好的可能方法似乎是为您的脚本保留一个固定名称并扩展 [=15=]
:
${0##*/}
并将其与名称匹配。如果扩展产生任何其他内容,则意味着脚本已被获取。另一种情况可能是用户重命名了它。所以它不是完全容易出错,但仍然应该完成我的工作。
如果您打算使用 Bourne shell (/bin/sh),只测试 $0 效果很好。
$ cat t
#!/bin/sh
if [ [=10=] == "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 上的命令 man sh 为 bash
带来手册页