To simplify printing shell output in many simple situations, I'd like a quick Ansible Playbook snippet to show just the stdout_lines
and stderr_lines
— but still keeping them distinct.
- name: demo output streams
shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
register: tout
- debug:
var: tout
gives this:
TASK [debug] **************************************************************
ok: [remote] => {
"tout": {
"changed": true,
"cmd": "echo hi stdout; echo ho stderr 1>&2; false; true",
"delta": "0:00:00.011020",
"end": "2022-02-24 16:19:25.812732",
"failed": false,
"msg": "",
"rc": 0,
"start": "2022-02-24 16:19:25.801712",
"stderr": "ho stderr",
"stderr_lines": [
"ho stderr"
],
"stdout": "hi stdout",
"stdout_lines": [
"hi stdout"
]
}
}
What I want is something more concise like this, or perhaps split, but still referenced by a single debug task in the Playbook. (Integrated into the shell task itself would be even more ideal, but I guess that's off the table.)
TASK [debug] **************************************************************
ok: [remote] => {
"tout": {
"stderr_lines": [
"ho stderr"
],
"stdout_lines": [
"hi stdout"
]
}
}
The false
and true
fluff just indicates that I simply want to see the command outputs, without Ansible-worrying about success or failure.
Of course I could use multiple debug
's, but that output becomes cumbersome when there are many of these quick-info tasks.
CodePudding user response:
you could do something like this:
- name: demo output streams
shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
register: tout
- debug:
var: result
vars:
result: "{{ {'tout': [{'stdout_lines': tout.stdout_lines}, {'stderr_lines': tout.stderr_lines}]} }}"
or using
- debug:
var: result
vars:
result: "{{ {'tout': { 'stdout_lines': tout.stdout_lines, 'stderr_lines': tout.stderr_lines} } }}"
if you want something easy to read, create a custom plugin: (here onlystd)
#!/usr/bin/python
class FilterModule(object):
def filters(self):
return {
'onlystd': self.onlystd
}
def onlystd(self, out, name = ''):
result= { 'stdout_lines': out['stdout_lines'], 'stderr_lines': out['stderr_lines'] }
if name != '':
result= { name: result }
return result
playbook to use it
- name: "make this working"
hosts: localhost
vars:
tasks:
- name: demo output streams
shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
register: tout
- debug:
var: tout | onlystd('tout') #if you want a name
- debug:
var: tout | onlystd #without name
results:
ok: [localhost] => {
"tout | onlystd('tout')": {
"tout": {
"stderr_lines": [
"ho stderr"
],
"stdout_lines": [
"hi stdout"
]
}
}
}
ok: [localhost] => {
"tout | onlystd": {
"stderr_lines": [
"ho stderr"
],
"stdout_lines": [
"hi stdout"
]
}
}
CodePudding user response:
Use selectattr
to filter the keys given by the result of the filter dict2items
on your dictionary. Then swap it back to a dictionary with items2dict
.
Given:
- name: demo output streams
shell: "echo hi stdout; echo ho stderr 1>&2; false; true"
register: tout
- debug:
var: tout | dict2items | selectattr('key', 'in', _keys_filter) | items2dict
vars:
_keys_filter:
- stdout_lines
- stderr_lines
This would yield:
TASK [demo output streams] ***************************************************
changed: [localhost]
TASK [debug] *****************************************************************
ok: [localhost] =>
tout | dict2items | selectattr('key', 'in', _keys_filter) | items2dict:
stderr_lines:
- ho stderr
stdout_lines:
- hi stdout