龙空技术网

如何安全退出 Bash 脚本

98dev 152

前言:

今天小伙伴们对“电脑出现脚本错误怎样修改”大致比较关注,我们都想要剖析一些“电脑出现脚本错误怎样修改”的相关内容。那么小编在网上汇集了一些对于“电脑出现脚本错误怎样修改””的相关资讯,希望我们能喜欢,看官们快快来学习一下吧!

一、概述

一个好的 Bash 脚本通常会在执行它包含的命令之前执行一些检查。例如,执行管理命令的脚本应检查该脚本是否由 root 用户调用或是否具有sudo访问权限。如果权限较低的用户调用该脚本,它应该立即调用exit命令以停止其执行。然而,有那么简单吗?

在本教程中,我们将了解为什么exit命令不是退出 Bash 脚本的最佳方式。虽然这确实是最直接的方法,但不幸的是,它并不是最安全的方法。在这里,我们将探索其他方式。

2. 运行 Bash 脚本的两种方法

运行 Bash 脚本的一种常见方法是通过调用以其文件系统路径为前缀的脚本文件名,从 shell 会话中执行它。例如,要执行位于当前工作目录的文件名为myscript.sh的脚本,我们在调用前加上“./”:

$ ./myscript.sh

还有另一种运行脚本的方法,即通过在脚本调用前加上source关键字来获取脚本:

$ source ./myscript.sh

或者,我们也可以在source关键字的位置使用点:

$ . ./myscript.sh

2.1. 执行和获取 Bash 脚本的区别

当我们执行脚本时,Linux 会生成当前 shell 会话的子进程并在其中执行myscript.sh。我们的shell进程在等待脚本子进程退出时会阻塞,除非它是在后台执行的。

与执行脚本不同,采购它不会产生子进程。相反,脚本中的命令将直接在采购发生的当前流程中执行。

让我们看一些证据。

首先,我们将创建一个简单的脚本myscript.sh,它只调用ps命令:

#!/bin/bash

ps -f

接下来,让我们在执行之前使其可执行:

$ chmod +x myscript.sh

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 149 148 0 14:27 tty1 00:00:00 -bash

mlukman+ 262 149 0 14:45 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 263 262 0 14:45 tty1 00:00:00 ps -f

在上面的示例中,当前 shell 进程的 PID 为 149。我的 script.sh 的执行生成了 PID 为 262 的 Bash 子进程。该进程反过来作为具有 PID 的子进程执行了ps命令263。

现在,让我们尝试采购脚本:

$ source ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 149 148 0 14:27 tty1 00:00:00 -bash

mlukman+ 264 149 0 14:59 tty1 00:00:00 ps -f

如我们所见,调用ps命令的进程是当前 shell 进程的直接子进程。shell 会话没有中间 Bash 子进程。

2.2. exit命令在执行时与采购时的行为

继续,让我们看看如果我们在脚本中有一个退出命令会发生什么:

#!/bin/bash

ps -f

exit

echo We should not see this

执行脚本提供与以前相同的结果:

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 1 15:05 tty1 00:00:00 -bash

mlukman+ 25 10 0 15:06 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 26 25 0 15:06 tty1 00:00:00 ps -f

但是,采购行为与以前大不相同。

shell 会话将终止。由于 sourc 脚本直接在当前进程中执行其命令,因此脚本中的 exit 命令会终止当前进程,即 shell 会话。

我们可以从这个小实验中吸取的教训是,在Bash 脚本中使用exit命令并不总是安全的。我们需要使用一些技巧来安全地退出脚本。

3.返回命令

要退出源脚本,我们需要一个返回命令而不是退出命令:

#!/bin/bash

ps -f

return

echo We should not see this

如果我们获取脚本,我们将获得与仅使用ps命令的脚本版本相同的结果:

$ source ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 28 10 0 21:09 tty1 00:00:00 ps -f

但是,执行它会抛出一个错误:

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 29 10 0 21:24 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 30 29 0 21:24 tty1 00:00:00 ps -f

./myscript.sh: line 3: return: can only `return' from a function or sourced script

We should not see this

如错误消息中所述,return命令仅允许在函数或源脚本中使用,而在执行脚本时不允许使用。

3.1. 返回-退出组合

为了使脚本与执行和采购兼容,我们必须将返回命令和退出命令结合起来。

首先,我们通过将 STDERR 管道传输到/dev/来使return命令不输出错误消息:

return 2> /dev/

接下来,我们添加退出命令:

return 2> /dev/; exit

将这一行应用到我们的 myscript.sh 中:

#!/bin/bash

ps -f

return 2> /dev/; exit

echo We should not see this

最后,让我们尝试执行和获取脚本:

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 35 10 0 21:31 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 36 35 0 21:31 tty1 00:00:00 ps -f

$ source ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 37 10 0 21:31 tty1 00:00:00 ps -f

瞧!我们的脚本现在可以在两种调用方法中正常工作。但是我们完成了吗?并不真地。

3.2. 与复杂脚本不兼容

还记得用 return 命令执行脚本时出现的错误信息吗?

./myscript.sh: line 3: return: can only `return' from a function or sourced script

有趣的是,错误信息中提到了“function”。如果我们在函数中使用返回和退出组合方法,我们不好奇会发生什么吗?让我们将 return-and-exit 组合行移动到一个函数中并调用该函数:

#!/bin/bash

exitscript () {

return 2> /dev/; exit

}

ps -f

exitscript

echo We should not see this

接下来,我们将查看脚本是否仍然有效:

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 40 10 0 21:43 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 41 40 0 21:43 tty1 00:00:00 ps -f

We should not see this

$ source ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 15:05 tty1 00:00:00 -bash

mlukman+ 42 10 0 21:43 tty1 00:00:00 ps -f

We should not see this

不幸的是,从“我们不应该看到这个”行的回显可以明显看出,如果从函数内部调用,返回和退出组合方法将不再有效。

4. kill命令

我们在前面几节中探索的返回和退出组合技巧适用于执行和采购方法。但是,在函数中使用时,它会惨遭失败。我们需要找到一个新的把戏。

我们要在这里尝试的技巧似乎有点吓人。这是杀戮命令。

特别是,我们要让脚本自杀。好吧,不是真的。我们只是使用kill命令让它自己中断:

kill -SIGINT $$

SIGINT 选项告诉kill命令向引用的PID 发送中断信号,这是运行该命令的当前进程。类似于CTRL+C的工作方式,发送中断信号只会停止当前进程中仍在运行和排队的任何东西,无论它是 shell 会话进程还是它的 Bash 子进程。

让我们将它实现到脚本中,替换 return-and-exit 组合行:

#!/bin/bash

exitscript () {

kill -SIGINT $$

}

ps -f

exitscript

echo We should not see this

让我们测试修改后的脚本:

$ ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 Feb19 tty1 00:00:00 -bash

mlukman+ 113 10 0 07:01 tty1 00:00:00 /bin/bash ./myscript.sh

mlukman+ 114 113 0 07:01 tty1 00:00:00 ps -f

$ source ./myscript.sh

UID PID PPID C STIME TTY TIME CMD

mlukman+ 10 9 0 Feb19 tty1 00:00:00 -bash

mlukman+ 115 10 0 07:01 tty1 00:00:00 ps -f

除了额外的空行之外,脚本现在可以运行,表明kill命令成功地从一个函数中退出了脚本。但是,使用此方法的副作用是脚本执行会突然停止,从而无法正确返回退出代码。因此,我们应该限制仅在需要从函数中退出并且不需要退出代码时才使用此方法。

5.结论

在本文中,我们演示了执行和采购 Bash 脚本之间的区别,以及我们如何不能简单地使用 exit 命令退出脚本。我们探索了两种方法:返回和退出组合方法和中断方法。我们建议使用返回和退出组合方法,除非我们需要从函数内部退出,在这种情况下我们需要求助于中断方法。

作者: baeldung

源链接:

格式整理:IT运维技术圈

小编有话说

➤推荐服务:

向下滑动查看更多

点击【IT面试精选】查看全网最权威的一线大厂面试真题及面试经验,每天更新哦!

点击【IT路边社】查看实时更新的IT新闻资讯

点击【互联网资料存储站】获取全网最全运维流程文档、表格、脚本、架构、等保资料等

回复【加群】群满啦!~添加波哥微信拉您进群!

点击【安全加固】获取最新安全加固脚本

点击一键iptables脚本】获取iptables自动设置脚本


标签: #电脑出现脚本错误怎样修改