前言
ES的Java环境变量已设置,但是启动未生效。(Elasticsearch环境搭建参考:Elasticsearch环境搭建)
已经设置 了ES_JAVA_HOME环境变量启动ES,还会收到警告:
warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
本篇文章将了解到输出与重定向,Linux环境变量设置与读取相关内容。
分析ES的Java环境配置
分析ES启动命令脚本
当前目录
pwd
/home/es/elasticsearch-7.17.3
查看启动命令
vim bin/elasticsearch
第一行有效命令是执行环境变量设置脚本
source "`dirname "$0"`"/elasticsearch-env
这行命令的意思是:执行elasticsearch-env脚本,设置环境变量。
以下是该脚本 详细讲解:
- $0:在Shell脚本中,$0是一个特殊变量,反映脚本被调用时的实际路径和名称。
-
- 如果使用绝对路径(完整路径)执行脚本,则此脚本内$0的值就是完整路径+当前脚本名字;
- 如果使用相对路径执行脚本,则此脚本内$0的值就是相对于当前操作目录(pwd可查)的相对路径+当前脚本名字;
- dirname "$0":dirname返回给定路径的目录部分(也就是不包括最后名字那一部分)。所以,dirname "$0"会返回脚本自身所在的目录路径。由于$0可能包含空格或特殊字符,所以它被双引号包围起来,以确保正确处理。
- .../elasticsearch-env:这个部分将上述的目录路径与elasticsearch-env文件名组合起来,形成一个完整的路径,即基于当前操作目录的相对路径:bin/elasticsearch-env
- 在Shell脚本中,source 命令用于在当前shell环境中执行指定的脚本文件,而不是在子shell中。这意味着脚本中定义的任何变量、函数或更改的环境变量都会在source命令被调用的同一个shell环境中生效。
那么现在来看elasticsearch-env脚本中对JDK相关变量的设置
# now set the path to java
if [ ! -z "$ES_JAVA_HOME" ]; then
JAVA="$ES_JAVA_HOME/bin/java"
JAVA_TYPE="ES_JAVA_HOME"
elif [ ! -z "$JAVA_HOME" ]; then
# fallback to JAVA_HOME
echo "warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME" >&2
JAVA="$JAVA_HOME/bin/java"
JAVA_TYPE="JAVA_HOME"
else
# use the bundled JDK (default)
if [ "$(uname -s)" = "Darwin" ]; then
# macOS has a different structure
JAVA="$ES_HOME/jdk.app/Contents/Home/bin/java"
else
JAVA="$ES_HOME/jdk/bin/java"
fi
JAVA_TYPE="bundled JDK"
fi
- 在 Bash 中,[ ... ] 是一个测试条件表达式的结构,它用于评估一个条件是否为真(返回 0)或假(返回非 0)
- -z STRING:这个测试条件检查 STRING 是否为空(猜测-z来源自zero,也就是如果-z为true即字符串长度为0,那就是空串)。如果 STRING 的长度为 0,那么 -z STRING 为真。
- ! :这是一个逻辑非操作符,用于取反 !0=1, !1=0。
- if [ ! -z "$ES_JAVA_HOME" ]; then:结合上面解释这里就是使用$符号去引用环境变量ES_JAVA_HOMEES_JAVA_HOME,如果设置了该环境变量,那就会被读取到,那么就不是空串,因此-z判断为false,!取反结果就是为true,因此这里if判断就是true,于是执行该判断通过后面的语句
- >&2 的意思是将标准输出(stdout)重定向到标准错误(stderr)(这个内容感兴趣的话,可以阅读后边的【拓展知识】部分)
优先级
由上面脚本可以看到ES的Java环境变量的设置优先级:ES_JAVA_HOME > JAVA_HOME > bundled JDK
解释下就是:
- ES_JAVA_HOME:单独设置的环境变量ES_JAVA_HOME优先级最高,如果设置后,就会使用该变量的路径配置作为ES启动需要的JAVA环境;
- JAVA_HOME:安装JAVA并设置的环境变量JAVA_HOME,如果未指定ES_JAVA_HOME,则使用当前机器中安装JDK配置的JAVA_HOME,作为ES启动需要的JAVA环境;
- bundled JDK:使用的ES自带的JDK。也就是说如果当前机器呢,没有设置过 ES_JAVA_HOME,也没有安装过JDK环境,当然就没设置过JAVA_HOME,才会走到这个判断分支内,使用ES自带的JDK。
而这里,可以看到ES推荐指定ES_JAVA_HOME。对于ES而言使用JAVA_HOME环境变量配置作为ES启动所需要的Java环境是弃用的方式,建议使用ES_JAVA_HOME
但是呢,
我这里呢,实际上是在安装ES时候手动指定过ES环境变量
vim .bash_profile
export ES_JAVA_HOME=/home/es/elasticsearch-7.17.3/jdk
export ES_HOME=/home/es/elasticsearch-7.17.3
source .bash_profile
问题&现象
为什么在终端中启动会提示使用的弃用的JAVA_HOME方式(即使用的当前环境中已经安装的JDK8)呢?
warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
[root@polaris ~]#
[root@polaris ~]# su es
[es@polaris root]$ cd ~/elasticsearch-7.17.3/
[es@polaris elasticsearch-7.17.3]$
[es@polaris elasticsearch-7.17.3]$ bin/elasticsearch -d
warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
Future versions of Elasticsearch will require Java 11; your Java version from [/home/es/jdk1.8.0_411/jre] does not meet this requirement. Consider switching to a distribution of Elasticsearch with a bundled JDK. If you are already using a distribution with a bundled JDK, ensure the JAVA_HOME environment variable is not set.
warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME
Future versions of Elasticsearch will require Java 11; your Java version from [/home/es/jdk1.8.0_411/jre] does not meet this requirement. Consider switching to a distribution of Elasticsearch with a bundled JDK. If you are already using a distribution with a bundled JDK, ensure the JAVA_HOME environment variable is not set.
[es@polaris elasticsearch-7.17.3]$
简单回顾下安装ES的过程
首先,root用户进入一个终端会话,
然后创建es用户,
然乎su es切换到es用户进行es所有操作
然后在es的主目录(cd ~,对于es这个用户主目录是/home/es)下.bash_profile文件中配置了环境变量ES_JAVA_HOME和ES_HOME,并使用source命令执行使之在当前 shell 会话中立即生效(即当前Shell会话中能够立即读取设置的变量,而不是必须新开一个会话,才能查看到)
注意:如果打开了一个新的终端窗口(即一个新的 shell 会话),这些环境变量也会自动生效,因为 .bash_profile 会在新的 shell 会话开始时自动执行。
那么,问题似乎有了些头绪,对吧,记住一点(后面会考)新启动终端窗口,设置的环境变量就会自动生效。
环境变量设置与读取
环境变量设置两种方式:
一种是修改/etc/profile,另一种是修改用户主目录下的.bash_profile。
当你通过SSH登录或打开一个新的终端窗口时/etc/profile或者/home/es/.bash_profile会被加载,
区别在于:
/etc/profile里面配置的环境变量是系统级配置文件,对所有用户都有效;
/home/es/.bash_profile 或 /home/es/.bashrc:这是用户级的配置文件,只对特定用户(在这里是es用户)有效
另外继承关系:
如果用户主目录下~/.bash_profile(或.bash_login、.profile)文件中存在source ~/.bashrc这样的命令,那么.bashrc中的设置将被继承到登录shell中。但.bash_profile中的设置不会自动被.bashrc继承。
问题解决
回到问题来,设置过环境变量,但是查询环境变量查不到。
根据之前分析有了些头绪,
这时,想到了一个问题,那就是我保存的会话打开的快捷链接中的用户名、密码都是配置的root用户欸,然后切换到es用户去启动es,
由于登录(开启一个新的终端)时会设置环境变量,切换用户并不会设置环境变量。
所以,读取不到设置的环境变量ES_JAVA_HOME(因为root用户登录开启的终端窗口)
那么,只有es用户启动会话或者登录,才可以设置环境变量(因为环境变量是使用es用户配置在用户级环境变量表)。
根因
SSH登录或打开一个新的终端窗口时,才会执行环境变量的设置,切换用户并不会设置环境变量。
用户级环境变量的读取需要使用对应用户登录或打开新的终端窗口时才可读取到。
验证
root用户登录
使用root用户启动的会话获取不到设置的es用户级环境变量
我这个环境里面有java 1.8环境,所以走入了使用当前环境中已经存在的JDK的判断分支的逻辑,于是发出了警告。
es用户登录
现在使用es用户开启会话,可以获取到设置的es用户级环境变量
echo $ES_JAVA_HOME
/home/es/elasticsearch-7.17.3/jdk
且启动不会报JAVA环境警告了,表明就是使用的配置的ES_JAVA_HOME中配置的jdk
拓展知识
elasticsearch-env脚本中打印报错信息那一行
echo "warning: usage of JAVA_HOME is deprecated, use ES_JAVA_HOME" >&2
这里说一下 >&2 因为这个类似的用法在实际生产场景中用的非常多。
>&2 简单快速理解
- >:将输出重定向到文件(如果文件已存在,则覆盖它;如果文件不存在,则创建它)。
- &:取地址符&在这个上下文中用于指定一个文件描述符,而不是文件名。
- 2 :是标准错误的文件描述符
在 shell 脚本中,>&2 是一个重定向操作符,用于将输出(通常是标准输出,即文件描述符 1)重定向到另一个文件描述符,这里是 2,它通常代表标准错误(stderr)。
文件描述符
在 Unix 和 Unix-like 系统(如 Linux)中,文件描述符是一个非负整数,用于引用打开的文件、套接字或其他类型的 I/O 资源。最常见的文件描述符是:
- 0:标准输入(stdin)
- 1:标准输出(stdout)
- 2:标准错误(stderr)
重定向操作符
重定向操作符允许你更改这些文件描述符的默认行为。
- >:将输出重定向到文件(如果文件已存在,则覆盖它;如果文件不存在,则创建它)。
- >>:将输出追加到文件的末尾。
- >&2:将输出重定向到标准错误。
stdout与stderr:标准输出与标准错误
stdout(标准输出)和 stderr(标准错误)是 Unix 和 Unix-like 系统(如 Linux 和 macOS)中进程间通信的两个重要概念。这些概念通常与 shell 脚本、命令行工具和其他类型的程序一起使用,用于处理和传输数据。
stdout(标准输出)
- 定义:stdout 是进程用于发送正常输出(即非错误消息)到默认接收位置(通常是终端或命令行窗口)的文件描述符。其文件描述符编号为 1。
- 用途:程序使用 stdout 来显示其执行结果、输出数据或任何其他类型的常规信息。
- 默认行为:在命令行中运行程序时,stdout 的内容通常直接显示在命令行窗口上。
stderr(标准错误)
- 定义:stderr 是进程用于发送错误消息到默认接收位置(通常是终端或命令行窗口)的文件描述符。其文件描述符编号为 2。
- 用途:程序使用 stderr 来报告错误、警告或其他非正常的消息。这些消息与 stdout 的常规输出分开,以便用户或脚本可以更容易地区分它们。
- 默认行为:在命令行中运行程序时,stderr 的内容通常也直接显示在命令行窗口上,但可能会以不同的颜色或格式来突出显示,以便与 stdout 区分开来。
重定向
这两个流都可以被重定向到文件或其他命令,从而改变它们的默认行为。
- stdout 重定向:使用 > 或 >> 符号可以将 stdout 重定向到文件。例如,command > output.txt 会将 command 的输出保存到 output.txt 文件中。
- stderr 重定向:使用 2> 或 2>> 符号可以将 stderr 重定向到文件。例如,command 2> errors.txt 会将 command 的错误消息保存到 errors.txt 文件中。
合并输出
有时,你可能希望将 stdout 和 stderr 的输出合并到同一个地方。这可以通过将 stderr 重定向到与 stdout 相同的位置来实现,例如:
- command > output.txt 2>&1 会将 stdout 和 stderr 的输出都保存到 output.txt 文件中。
command > output.txt 2>&1
在 Unix 和类 Unix 系统中,当你使用重定向语法 command > output.txt 2>&1 时,这个命令的执行顺序和重定向的过程是这样的:
- 执行命令 (command): 首先,系统会执行你指定的命令 command。
- 标准输出重定向 (> output.txt): 接着,命令的标准输出(stdout,文件描述符为 1)会被重定向到 output.txt 文件中。这意味着原本会输出到终端的标准输出内容现在会被写入到这个文件中。
- 标准错误重定向 (2>&1): 在标准输出重定向之后,2>&1 会将标准错误(stderr,文件描述符为 2)重定向到当前标准输出(stdout)所指向的位置。由于标准输出已经被重定向到 output.txt,因此标准错误也会被写入到同一个文件 output.txt 中。
这个顺序很重要。
示例
考虑一个名为 my_program 的命令行程序,它可能会输出一些常规结果到 stdout,并在遇到错误时输出错误消息到 stderr。在终端中运行该程序时,用户将看到常规结果和错误消息分别显示(可能是以不同的颜色或前缀)。如果用户希望将这两个流的输出都保存到一个文件中,他们可以使用类似 my_program > output.txt 2>&1 的命令来合并输出。