《SHELL脚本在crontab环境下执行失败问题处理》>> 探索SHELL运行模式和加载环境变量【实践+实验】
- 1 现象描述
- 2 分析
- 3 解决方法
- 4 深层研究
- 4.1 shell
- 4.2 shell脚本的环境变量
- 4.3 shell脚本四种执行方法
- 4.4 source 、.、./、bash 的区别
- 4.5 shell常用的一些参数
- 4.6 shell常见的命令
- ① 查看当前shell
- ② crontab 定时任务
- ③ 2>&1 标准错误输出
- ④ 环境变量生效
- 5 shell 模式
- 5.1 四种模式判定方法
- 5.2 执行脚本
- 5.3 环境变量
1 现象描述
在suse 10 linux环境中部署crontab脚本,用以定时重启应用进程。具体包含:使用nohup命令启动tongweb应用进程,具体命令片段为:cd /tongweb/bin;nohup ./startserver.sh >/dev/null &
。该进程为root用户启动。在测试环境,无论单条命令执行,还是定时执行整个脚本,都是正常的。但是上线生产环境后,执行失败。
2 分析
进行试验,发现脚本在前台执行的时候均正常,在crontab后台执行会失败。经阅资料,发现crontab执行脚本失败的基本原因是,环境变量未加载,即/etc/profile。本质是:bash脚本登录模式默认加载/etc/profile文件,而非登录模式默认不加载/etc/profile文件。
3 解决方法
1、脚本中加载环境变量
#!/bin/bash
source /etc/profile
2、crontab前加载环境变量
0 8 * * * source /etc/profile;sh /tongweb/tongwebrestart.sh 2<&1
3、使用登录模式调用脚本
0 8 * * * /bin/bash -l /tongweb/tongwebrestart.sh 2<&1
4 深层研究
4.1 shell
Shell,区别于内核被称为壳,(Shell 脚本)是一种命令行解释器,用于与操作系统进行交互和执行命令。bash是一种shell,还有ksh等。
4.2 shell脚本的环境变量
脚本中的命令是在子shell中执行,子shell只能继承父shell的环境变量,而无法修改父shell的环境变量。
4.3 shell脚本四种执行方法
shell脚本通常以#!/bin/bash
开头。
#!一般称为shebang。在Unix中,用sharp或hash(有时是mesh)称呼字符#,用bang称呼!,因而shebang代表#!
序号 | 方法 | 说明 | 执行位置 | 权限 | 是否保存变量结果 |
---|---|---|---|---|---|
方法1 | 工作目录执行 | cd /home/test;./hello.sh | 子shell中执行 | 需要执行权限 | 不保存 |
方法2 | 绝对路径执行 | /home/test/hello.sh | 子shell中执行 | 需要执行权限 | 不保存 |
方法3 | 使用bash 或sh 执行 | cd /home/test;sh hello.sh 或 cd /home/test;bash hello.sh | 子shell中执行 | 无需执行权限,可不写#!/bin/bash | 不保存 |
方法4 | 使用source 或. 执行注意: . 与脚本间有空格 | cd /home/test;source hello.sh 或 cd /home/test;. hello.sh | 在shell中直接执行 | 无需执行权限,可不写#!/bin/bash | 保存 |
4.4 source 、.、./、bash 的区别
执行方式 | 子shell | 脚本中变量是否保存 | 是否需要执行权限 |
---|---|---|---|
./*.sh | 启动新的子shell | 不保存变量结果 | 需要 |
sh ./*.sh | 启动新的子shell | 不保存变量结果 | 不需要 |
bash ./*.sh | 启动新的子shell | 不保存变量结果 | 不需要 |
source ./*.sh | 在当前shell进程中执行脚本 | 保存变量结果 | 不需要 |
. ./*.sh | 在当前shell进程中执行脚本 | 保存变量结果 | 不需要 |
4.5 shell常用的一些参数
参数 | 说明 |
---|---|
-i | 如果有 -i 选项,shell 将交互地执行 ( interactive )。 |
-l | 选项使得 bash 以类似登录 shell (login shell) 的方式启动 |
-r | 如果有 -r 选项,shell 成为受限的 ( restricted ) |
-- | 选项结束标志,后面的内容当做文件名或参数,即使他们以-开头 |
-s | 如果有 -s 选项,或者如果选项处理完以后,没有参数剩余,那么命令将从标准输入读取。 这个选项允许在启动一个交互 shell 时可以设置位置参数。 |
--login | 同-l |
--noprofile | 不读取系统范围的启动文件 /etc/profile 或者任何个人初始化文件~/.bash_profile, ~/.bash_login, 或 ~/.profile 。默认情况下, bash 在作为登录 shell 启动时读取这些文件 |
--norc | 如果 shell 是交互的,不读取/执行个人初始化文件 ~/.bashrc 这个选项在shell 以 sh 命令启动时是默认启用的 |
--recfile file | 在交互式shell,指定初始化文件是file而不是~/.bashrc |
--version | 版本信息 |
————————————————
本节部分内容参考CSDN博主「Code_LT
」的原创文章,十分感谢,欢迎大家点击原文关注作者。原文链接:《交互式shell和非交互式shell、登录shell和非登录》
————————————————
4.6 shell常见的命令
① 查看当前shell
else@suse-linux:~> echo $SHELL
/bin/bash
② crontab 定时任务
0 8 * * * source /etc/profile;sh /tongweb/tongwebrestart.sh>/dev/null 2<&1
③ 2>&1 标准错误输出
关键字 | 说明 |
---|---|
1> stdout | 表示标准输出,默认是1 |
2> stderr | 表示标准错误 |
& | 表示等同于 |
2>&1 | 表示标准错误重定向,等同于标准输出 |
④ 环境变量生效
source /etc/profile
5 shell 模式
根据 POSIX 标准,Shell 分为登录(login)、非登录(non-login)
和交互(interactive)、非交互(non- interactive)
两个维度的处理。因此 bash 也不例外。
四种模式 | 进入方式 | 说明 |
---|---|---|
登录模式(login) | 或 su - 用户 | 用户名、密码登录后才能进入的shell |
非登录模式(non-login) | su 用户 | Shell 表示不需要用户名和密码,比如在登录 Shell 之后再执行的 bash,就产生了一个非登录 Shell (一些图形界面系统,有 terminal,这时,这些终端产生的一个 shell就是非登录 Shell);同时 logout 不能在非登录 Shell 中执行。 |
交互模式(interactive) | ssh登录到对端或图形界面启动terminal | 终端上执行 bash(shell),shell 等待你的输入来执行实际的命令 |
非交互模式(non- interactive) | ssh不登录直接执行命令ssh tongweb@192.168.8.130 'echo $-' 或者 crontab定时执行也是非交互式 | 读取脚本,从头读到尾执行结束。 |
5.1 四种模式判定方法
# 1、交互模式:执行命令,返回值含i为。如下:
else@suse-linux:~> echo $-
himBH
# 2、非交互模式:执行命令,返回值不含i。如下:
else@suse-linux:~> ssh tongweb@192.168.8.130 'echo $-'
Password:
hBC #也有返回值为hB
# 3、登录模式:执行命令,返回值为shopt -s login_shell。如下:
else@suse-linux:~> shopt -p login_shell
shopt -s login_shell
# 4、非登录模式:执行命令,返回值为shopt -u login_shell。如下:
else@suse-linux:~> shopt -p login_shell
shopt -u login_shell
5.2 执行脚本
# 1、在登陆模式下执行
/bin/bash -l script.sh
# 2、在交互模式下执行
/bin/bash -i script.sh
5.3 环境变量
登陆方式 | 环境变量 |
---|---|
bash 是作为交互的登录 shell 启动的,或者是一个非交互的 shell 但是指定了 --login 选项 | 首先读取并执行 /etc/profile 中的命令,只要那个文件存在。 读取那个文件之后,它以如下的顺序查找 ~/.bash_pro‐ file, ~/.bash_login, 和 ~/.profile, 从存在并且可读的第一个文件中读取并执行其中的命令。 --noprofile 选项可以用来在 shell 启动时阻止它这样做。 |
shell 退出时 | bash 读取并执行文件 ~/.bash_logout 中的命令,只要它存在。 |
一个交互的 shell 但不是登录 shell 启动时 | bash 从文件 ~/.bashrc 中读取并执行命令,只要它存在。可以用 --norc 选项来阻止它这样做。 --rcfile file 选项将强制 bash 读取并执行文件 file 中的命令,而不是 ~/.bashrc 中的 |
bash 以非交互的方式启动时例如在运行一个 shell 脚本时 | 在环境中查找变量 BASH_ENV ,如果它存在则将它的值展开,使用展开的值作为一个文件的名称,读取并执行。Bash 运作的过程就如同执行了下列命令: if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 但是没有使用 PATH 变量的值来搜索那个文件名。 |
bash 以名称 sh 启动 | 它试图模仿 (mimic) sh 历史版本的启动过程,尽可能地相似,同时也遵循 POSIX 标准。 1、当作为交互式登录 shell 启动时,或者是非交互但使用了 --login 选项启动的时候,它首先尝试读取并执行文件 /etc/profile 和 ~/.profile, 中的命令. 选项 --noprofile 用于避免这种行为 2、当使用命令 sh 来启动一个交互式的 shell 时, bash 查找环境变量 ENV, 如果有定义的话就扩展它的值,然后使用扩展后的值作为要读取和执行的文件 的名称.由于使用 sh 启动的 shell 不会读取和执行任何其他的启动文件,选项 --rcfile 没有意义 .使用名称 sh 启动的非交互的 shell 不会读取任何其他启动文件. 3、当以 sh 启动时, bash 在读取启动文件之后进入 posix 模式. |
bash 以 posix 模式启动时,(和使用 --posix 命令行参数效果相同) | 遵循 POSIX 标准. 这种模式下,交互式 shell 扩展 ENV 环境变量的值,读取并执行以扩展后值为文件名的配置文件. 不会读取其他文件 .Bash 试着检测它是不是由远程 shell 守护程序,通常为 rshd 启动的.如果 bash 发现它是由 rshd 启动的,它将读取并执行 ~/.bashrc 文件中的命令, 只要这个文件存在并且可读.如果以 sh 命令启动,它不会这样做. 选项 --norc 可以用来阻止这种行为,选项 --rcfile 用来强制读取另一个文件,但是通常rshd 不会允许它们, 或者用它们来启动 shell. |
shell 是以与真实用户(组) id 不同的有效用户(组) id 来启动并且没有 - 选项 | 不会读取启动文件, 也不会从环境中继承 shell 函数. 环境变量中如果出现 SHELLOPTS, 它将被忽略.有效用户 id 将设置为真实用户 id. 如果启动时给出了 - 选项,那么启动时的行为是类似的, 但是不会重置有效用户 id. |