英文:
How do I get the output of a linux command /usr/java/jdk-1.8/bin/java -version using ansible?
问题
我正在尝试编写一个脚本,以获取安装在特定位置的Java版本。
当我使用下面的任务并提供完整路径时,返回的输出为空。当我将shell命令设置为java -version
而不带路径时,它可以正常工作。
英文:
I am trying to write a script to fetch the java version which is installed in a specific location.
When I use the below task with the full path, the returned output is empty. When I give the shell command as java -version
without the path, it works fine.
- name: Fetch Java version from location
shell: /usr/java/jdk-1.8/bin/java -version 2>&1 | awk -F '"' '/version/ {print $2}'
register: java_version_from_path
- name: Display the java version from the java location
debug:
msg: "{{ java_version_from_path.stdout }}"
答案1
得分: 2
您的代码按照原样对我有效,但在测试时,我输入错误的路径,出现了与您相同的行为。
因为您在管道中使用了一个 shell
任务,如果管道中的第一个命令失败,错误实际上被抑制了。考虑一下这个例子:
$ false | echo hello
hello
$ echo $?
0
第一个命令失败了,但没有办法知道。这正是我在本地运行Playbook时看到的行为,也可能是您问题的原因。
如果您将完整的命令行复制并粘贴到您的Shell中运行,它是否有效?如果只复制并粘贴 ../java -version
部分呢?
对于这种类型的任务,通常在Ansible中进行文本解析比使用 awk
更简单,类似这样:
- hosts: localhost
gather_facts: false
tasks:
- name: 从位置获取Java版本
command: /usr/java/jdk-17.0.2/bin/java -version
register: java_version_from_path
- name: 显示从Java位置获取的Java版本
debug:
msg: >-
{{
(
java_version_from_path.stderr_lines |
select('search', 'version') |
first
).split('"')[1]
}}
在我的系统上,这会产生:
TASK [从位置获取Java版本] *****************************************************************
changed: [localhost]
TASK [显示从Java位置获取的Java版本] **************************************************
ok: [localhost] => {
"msg": "17.0.2"
}
通过在Ansible中执行文本解析,我们可以使用 command
任务,而不是 shell
,并且如果java
命令中有shell管道错误,将会传播到Playbook,我们会看到失败的信息:
TASK [从位置获取Java版本] *****************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "cmd": "/usr/java/jdk-1.8/bin/java -version", "msg": "[Errno 2] No such file or directory: b'/usr/java/jdk-1.8/bin/java'", "rc": 2, "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
英文:
Your code works for me as written, but while testing it I mis-typed the path and got the same behavior as you.
Because you're using a shell
task with a pipe, if the first command in the pipe fails the error is effectively suppressed. Consider this:
$ false | echo hello
hello
$ echo $?
0
The first command fails, but there's no way to tell. That's exactly the behavior I was seeing running the playbook locally, and it may be the cause of your problem.
If you copy and paste the full command line into your shell and run it, does it work? What if you just copy and paste the ../java -version
part?
For this sort of task it's often simpler to do the text parsing in ansible rather than using awk
; something like this:
- hosts: localhost
gather_facts: false
tasks:
- name: Fetch Java version from location
command: /usr/java/jdk-17.0.2/bin/java -version
register: java_version_from_path
- name: Display the java version from the java location
debug:
msg: >-
{{
(
java_version_from_path.stderr_lines |
select('search', 'version') |
first
).split('"')[1]
}}
On my system, this produces:
TASK [Fetch Java version from location] *****************************************************************
changed: [localhost]
TASK [Display the java version from the java location] **************************************************
ok: [localhost] => {
"msg": "17.0.2"
}
By performing the text parsing in Ansible, we can use a command
task, rather than shell
, and without that shell pipeline errors in the java
command will propagate to the playbook and we'll see the failure:
TASK [Fetch Java version from location] *****************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "cmd": "/usr/java/jdk-1.8/bin/java -version", "msg": "[Errno 2] No such file or directory: b'/usr/java/jdk-1.8/bin/java'", "rc": 2, "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论