Reputation: 43
Hi I am reading content from a file.
The file contains the following content.
======
interface And
public void and(int, int);
public void nand(int, int);
======
interface Or
public void or(int, int); public void nor(int, int);
======
interface Xor
public void xor(int, int); public void xnor(int, int);
======
interface Not
public void not(int);
======
class BitWise extends And, Or, Xor, Not
// Implementation of the Interfaces goes here
======
I am trying to read only the interfaces
I went through this How to read a particular part of file in ansible
---
- name: Read the Interfaces
hosts: 127.0.0.1
connection: local
vars:
- file_path: " {{ playbook_dir }}/input_file.txt"
- my_interfaces: []
tasks:
- name: Reading the interfaces
set_fact:
my_interfaces: "{{ my_interfaces + [ item ] }}"
with_lines: "cat {{file_path}}"
when: item is search('^interface.+?=*')
- name: Printing all the interfaces
debug:
var: my_interfaces
The Programs Output is
ok: [127.0.0.1] => {
"my_interfaces": [
"interface And",
"interface Or",
"interface Xor",
"interface Not"
]
}
But The desired output is
ok: [127.0.0.1] => {
"my_interfaces": [
"interface And \n public void and(int, int) \n public void nand(int, int)",
"interface Or \n public void or(int, int) \n public void nor(int, int)",
"interface Xor \n public void xor(int, int) \n public void xnor(int, int)",
"interface Not \n public void not(int)",
]
}
I think that I am doing something wrong in the regular expression part. But I don't know how to correct it to get the desired output.Could anyone help me to solve the problem. And is there any other way than this to do the same task.
Upvotes: 2
Views: 2290
Reputation: 4777
You can combine filters and tests to get your desired result:
---
- hosts: localhost
gather_facts: false
vars:
content: "{{ lookup('file', 'filename') }}"
tasks:
- name: "split file into blocks"
set_fact:
content: "{{ content.split('======') }}"
- debug:
msg: "{{ content }}"
- name: "remove white space from start and end of blocks"
set_fact:
content: "{{ content | map('trim') | list}}"
- debug:
msg: "{{ content }}"
- name: "select blocks that start with interface"
set_fact:
content: "{{ content | select('search', '^interface') | list}}"
- debug:
msg: "{{ content }}"
You can also combine all the steps in a single command:
---
- hosts: localhost
gather_facts: false
vars:
content: "{{ lookup('file', 'filename') }}"
tasks:
- name: "fetch interfaces"
set_fact:
content: "{{ content.split('======') | map('trim') | select('search', '^interface') | list }}"
- debug:
msg: "{{ content }}"
This will return:
[u'interface And\n\npublic void and(int, int);\n\npublic void nand(int, int);',
u'interface Or\n\n public void or(int, int);\n\n public void nor(int, int);',
u'interface Xor\n\n public void xor(int, int);\n\n public void xnor(int, int);',
u'interface Not\n\n public void not(int);']
Upvotes: 2
Reputation: 163437
In your pattern ^interface.+?=*
this part .+?
is non greedy so the engine would match 1+ times as least as possible. This part =*
matches an equals sign 0+ times.
When there is no equals sign in the interface, it would only match interface
followed by a space if the dot does not match a newline.
You have to enable that the dot matches a newline (use an inline modifier (?s)
if supported) if you want to use your pattern. Use a capturing group or a positive lookahead to not match the newline and the equals signs but make sure that it is there.
(?s)^interface\b.+?(?=\r?\n=)
Another option could be to match interface and the rest of the line. Then repeat matching lines as long as the next line does not start with an equals sign using a negative lookahead (?!=)
^interface\b.*(?:\r?\n(?!=).*)*
Upvotes: 0
Reputation: 68104
Once you have the list of the headlines in my_interfaces it would be possible to use sed and print the range of the lines.
The tasks below
- command: "sed -n '/{{ item }}/,/======/p' {{ file_path }}"
register: result
loop: "{{ my_interfaces }}"
- set_fact:
my_ifc: "{{ my_ifc|default([]) + [ item.stdout_lines ] }}"
loop: "{{ result.results }}"
- debug:
var: my_ifc
give
"my_ifc": [
[
"interface And",
"",
"public void and(int, int);",
"",
"public void nand(int, int);",
"",
"======"
],
[
"interface Or",
"",
" public void or(int, int);",
"",
" public void nor(int, int);",
"======"
],
[
"interface Xor",
"",
" public void xor(int, int);",
"",
" public void xnor(int, int);",
"======"
],
[
"interface Not",
"",
" public void not(int);",
"======"
]
]
(formatting wip ...)
Upvotes: 1