首先,介绍一下遇到的问题:
同事设置定时任务执行脚本,却显示无法执行,但是可以直接执行脚本,同事怀疑是定时任务没有成功设置到该用户上。导致无法识别命令,大概内容如下:此处为了简略,大概写一个定时
[hadoop@hadoop-31-150 ~]$ crontab -e
no crontab for hadoop - using an empty one
crontab: installing new crontab
[hadoop@hadoop-31-150 ~]$ crontab -l
* * * * * /home/hadoop/test.sh > /home/hadoop/test.log
因为同事怀疑没有设定了用户,所以用root用户查看了目录/var/spool/cron
[root@hadoop-31-150 ~]# ll /var/spool/cron
total 4
-rw-------. 1 hadoop hadoop 55 Jan 9 15:09 hadoop
[root@hadoop-31-150 ~]# cat /var/spool/cron/hadoop
* * * * * /home/hadoop/test.sh > /home/hadoop/test.log
确实成功为该用户配置了定时任务,回头再来看看报错信息吧:
[hadoop@hadoop-31-150 ~]$ cat /var/spool/mail/hadoop
From hadoop@hadoop-31-150 Thu Jan 9 15:16:02 2020
Return-Path: <hadoop@hadoop-31-150>
X-Original-To: hadoop
Delivered-To: hadoop@hadoop-31-150
Received: by hadoop-31-150 (Postfix, from userid 1005)
id 77A88108912B; Thu, 9 Jan 2020 15:16:01 +0800 (CST)
From: "(Cron Daemon)" <hadoop@hadoop-31-150>
To: hadoop@hadoop-31-150
Subject: Cron <hadoop@hadoop-31-150> /home/hadoop/test.sh > /home/hadoop/test.log
Content-Type: text/plain; charset=UTF-8
Auto-Submitted: auto-generated
Precedence: bulk
X-Cron-Env: <XDG_SESSION_ID=4663>
X-Cron-Env: <XDG_RUNTIME_DIR=/run/user/1005>
X-Cron-Env: <LANG=en_US.UTF-8>
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/hadoop>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=hadoop>
X-Cron-Env: <USER=hadoop>
Message-Id: <20200109071601.77A88108912B@hadoop-31-150>
Date: Thu, 9 Jan 2020 15:16:01 +0800 (CST)
/home/hadoop/test.sh: line 3: java: command not found
这里先来看下test.sh 脚本内容:
[hadoop@hadoop-31-150 ~]$ cat test.sh
#!/bin/sh
java -version
[hadoop@hadoop-31-150 ~]$
很简单的一个执行java ,报错显示找不到java 命令,但是确实给hadoop配置了java 在shell窗口和执行脚本都可以执行
[hadoop@hadoop-31-150 ~]$ java -version
java version "1.8.0_152"
Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)
[hadoop@hadoop-31-150 ~]$ ./test.sh
java version "1.8.0_152"
Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)
因为这个原因同事怀疑是用户问题,但是再一次看报错邮件时,发现了端倪。定时任务打印出了执行脚本时的环境变量
X-Cron-Env: <PATH=/usr/bin:/bin>
确实没有java的路径,想起了之前学到的bash的四种执行命令:1.交互式登录执行 ,2.非交互式登录执行 3.交互式非登录执行 4.非交互式非登录执行 这四种不同的执行命令方式会加载不同的配置文件。可以通过命令
[hadoop@hadoop-31-150 ~]$ man bash
INVOCATION 部分内容如下:
大概就是讲bash执行命令时候加载文件顺序如下图
所以,此种情况下,定时任务执行的命令应该是非交互式非登录的执行命令,不加载任何配置文件,但会获取$BASH_ENV
所以改一下定时任务为
[hadoop@hadoop-31-150 ~]$ crontab -l
* * * * * export BASH_ENV=/opt/conf/java_env.sh;/home/hadoop/test.sh > /home/hadoop/test.log
发现仍然无法执行,再次查看man bash INVOCATION 中有一句话
A non-interactive shell invoked with the name sh does not attempt to read any other startup files.
使用sh 调用非交互shell时,不会加载任何启动文件。虽然sh是bash的软连接,但是当sh启动时,bash仍会尽可能的接近sh启动。所以将 test.sh的启动头改为#!/bin/bash
[hadoop@hadoop-31-150 ~]$ cat test.sh
#!/bin/bash
java -version
再次等待定时任务,果然,执行成功。但是此种方法还需要另行设置BASH_ENV,有没有更简便的方法呢?当然有,那就是编辑test.sh启动头为#!/bin/bash --login ,通过mam bash INVOCATION 部分可以看到,当指定--login时,会加载配置文件/etc/profile,和~/.bash_profile或者 ~/.bash_login或者 ~/.profile。这样以登录式的执行文件,便与登录到服务器shell执行命令时的环境参数一样了。所以相比上面那种方法,这种更为简单。
---------------------------------------------------------------------------------------------
顺便大概记录下之前遇到的相关问题。
背景:需要java程序中调用hadoop-daemon.sh脚本启动服务,后发现无法调用成功,还是环境变量的事情。
问题解决:发现是因为该java程序是由脚本启动,在脚本中定义了环境变量,与外部配置环境变量冲突,当此java程序调用hadoop-daemon.sh时,hadoop-daemon.sh脚本会继承java启动脚本中的环境变量,故无法成功启动。更改java启动脚本中环境变量后解决!