确定shell脚本是通过"引用"执行的

13 浏览
0 Comments

确定shell脚本是通过"引用"执行的

一个shell脚本是否可以测试它是通过source执行的呢?也就是说,比如说,

$ source myscript.sh
$ ./myscript.sh

myscript.sh能分辨出这些不同的shell环境吗?

0
0 Comments

(Determining whether shell script was executed "sourcing" it)这个问题的出现的原因以及解决方法

问题的出现原因:

在编写shell脚本时,我们可能会遇到一种情况,即通过source命令来运行脚本。当我们使用source命令来运行脚本时,脚本中的代码会在当前shell环境下执行,而不是启动一个新的子shell来执行。在这种情况下,我们可能需要根据脚本是通过直接执行还是通过source命令执行来做出不同的处理。因此,我们需要一种方法来确定脚本是通过source命令执行还是直接执行。

解决方法:

我们可以使用${BASH_SOURCE[0]}和$0这两个变量来判断脚本是通过source命令执行还是直接执行。在bash脚本中,${BASH_SOURCE[0]}表示当前脚本的路径,$0表示当前脚本的文件名。如果脚本是通过source命令执行的,那么${BASH_SOURCE[0]}和$0的值是相同的。如果脚本是直接执行的,那么${BASH_SOURCE[0]}和$0的值是不同的。

下面是一个可以判断脚本是通过source命令执行还是直接执行的示例代码:

[[ ${BASH_SOURCE[0]} = $0 ]] && main "$@"

在这个示例代码中,[[ ${BASH_SOURCE[0]} = $0 ]]表示判断${BASH_SOURCE[0]}和$0的值是否相等,如果相等,则执行后面的main "$@"代码。main "$@"表示调用main函数并传递所有的命令行参数。这样,当脚本是通过直接执行时,main函数将会被调用;当脚本是通过source命令执行时,main函数不会被调用。

通过以上的解决方法,我们可以根据脚本是通过source命令执行还是直接执行来做出不同的处理,从而更好地控制脚本的执行逻辑。

0
0 Comments

判断shell脚本是通过执行还是通过引用执行的问题是在Sam的需求中出现的。他希望有一个名为`myscript`的脚本,满足以下条件:

1. 不能直接通过`myscript`的名称来执行(也就是没有`chmod a-x`权限)

2. 不能通过`sh myscript`或`bash myscript`间接执行

3. 只有通过引用执行(`. myscript`)时才会运行其中的函数和命令

首先需要考虑以下几点:

1. 通过名称直接调用脚本(`myscript`)需要在脚本的第一行添加类似于`#!/bin/bash`的内容,这将决定将调用哪个已安装的bash可执行文件(或符号链接)来运行脚本。这将创建一个新的shell进程。脚本文件本身需要具有可执行权限。

2. 通过使用脚本的(路径+)名称作为参数调用shell二进制文件(`sh myscript`)与第一点相同,唯一的区别是不需要设置可执行标志,也不需要添加带有hashbang的第一行。唯一需要的是调用用户需要对脚本文件进行读取访问。

3. 通过引用其文件名(`. myscript`)调用脚本与第一点非常相似,唯一的区别是不会创建一个新的shell进程。所有脚本的命令都在当前shell中执行,使用其环境(并且还会将其环境中的任何(新)变量设置或更改“污染”当前环境。)

对于第一点:

要实现很容易:`chmod a-x myscript`将阻止`myscript`直接执行。但是这不会满足第二点和第三点的要求。

对于第二点和第三点:

要实现更困难。通过`sh myscript`调用需要对文件具有读取权限。因此,一个明显的解决方法似乎是使用`chmod a-r myscript`。然而,这也会禁止第三点:您将无法引用脚本。

那么在脚本中使用`Bashism`的方式怎么样呢?`Bashism`是一种其他shell不理解的特定操作方法:使用特定的变量、命令等。这可以在脚本中使用来检测此条件并“处理”它(例如“显示warning.txt”,“发送邮件给管理员”等)。但是,除非您通过调用`exit`来终止shell,否则绝对不会阻止`sh`、`bash`或任何其他shell读取和尝试执行脚本中的所有后续命令/行。

假设:

1. 脚本使用`#!/bin/bash`作为第一行,

2. 用户已将Bash设置为其shell,并且正在从Bash中调用以下表中的命令,并且它是他们的“登录shell”。

3. `sh`可用,并且它是指向`bash`或`dash`的符号链接。

这将意味着以下调用是可能的,并列出环境变量的值:

vars+invok's   | ./scriptname | sh scriptname | bash scriptname | . scriptname
---------------+--------------+---------------+-----------------+-------------
$0             | ./scriptname | ./scriptname  | ./scriptname    | -bash
$SHLVL         | 2            | 1             | 2               | 1
$SHELLOPTS     | braceexpand: | (empty)       | braceexpand:..  | braceexpand:
$BASH          | /bin/bash    | (empty)       | /bin/bash       | /bin/bash
$BASH_ARGV     | (empty)      | (empty)       | (empty)         | scriptname
$BASH_SUBSHELL | 0            | (empty)       | 0               | 0
$SHELL         | /bin/bash    | /bin/bash     | /bin/bash       | /bin/bash
$OPTARG        | (empty)      | (empty)       | (emtpy)         | (emtpy)

现在,您可以在文本脚本中添加逻辑:

- 如果`$0`不等于`-bash`,则执行`exit $SOMERETURNVALUE`。

如果通过`sh myscript`或`bash myscript`调用脚本,则会退出调用的shell。如果在当前shell中运行,它将继续运行。(警告:如果脚本有任何其他`exit`语句,您的当前shell将被“终止”...)

因此,在不可执行的`myscript.txt`中的开头添加类似以下内容可能会实现您的目标:

echo BASH=$BASH
test x${BASH} = x/bin/bash && echo "$? :    FINE.... You're using 'bash ...'"
test x${BASH} = x/bin/bash || echo "$? :    RATS !!! -- You're not using BASH and I will kick you out!"
test x${BASH} = x/bin/bash || exit 42
test x"${0}" = x"-bash"    && echo "$? :    FINE.... You've sourced me, and I'm your login shell."
test x"${0}" = x"-bash"    || echo "$? :    RATS !!! -- You've not sourced me (or I'm not your bash login shell) and I will kick you out!"
test x"${0}" = x"-bash"    || exit 33

感谢您的详细分析。很棒的答案。我希望能给您不止一个赞的机会。

0
0 Comments

原因:用户想要判断shell脚本是通过直接运行还是通过引用执行的。

解决方法:在脚本中添加一行指示语句,提示用户应该通过引用方式运行脚本。具体做法是在脚本的开头添加以下代码:

#!/bin/echo Should be run as: source

这样,当用户通过直接运行脚本时,会显示一条提示信息告诉用户应该通过引用方式运行。而当用户通过引用方式运行脚本时,脚本会正常执行。

以下是一个示例脚本:

#!/bin/echo Should be run as: source
export SOMEPATH="/some/path/on/my/system"
echo "Your environment has been set up"

当用户通过直接运行该脚本时,会得到以下输出:

$ ./myscript.sh
Should be run as: source ./myscript.sh

当用户通过引用方式运行该脚本时,会得到以下输出:

$ source ./myscript.sh
Your environment has been set up

需要注意的是,用户仍然可以通过运行`sh ./myscript.sh`来绕过这个判断,但至少在三种情况中有两种是符合预期行为的。

这种方法可能并不完美,但是对于解决这个困扰已久的问题来说是一种巧妙的方式。

0