2

I'm trying to read from a list of CSV files (fileglob) and the files have a standard naming convention. Just wanted to read the CSV files using read_csv and register/set_fact them to the filename, which should be the variable name.

The files are

apples.csv
pears.csv
grapes.csv

What I've tried, (its close but not correct)

- name: "Read into dynamic variables"
  read_csv:
    path: "{{ item }}"
  with_fileglob:
    - "/tmp/fruits/*.csv"
  fruit_name: "{{ item | basename | regex_replace('.csv') }}"
  register: "fruit_{{ fruit_name }}"

So ideally want to get the contents of each CSV to be part of variable, e.g. fruit_apples which can be later re-used in other plays.

2 Answers 2

4

For example, given the files

shell> tree fruits/
fruits/
├── apples.csv
├── grapes.csv
└── pears.csv

0 directories, 3 files
shell> cat fruits/apples.csv 
red,big,20
green,small,10
shell> cat fruits/grapes.csv 
red,big,20
black,small,10
shell> cat fruits/pears.csv 
green,big,30
yellow,small,20

Read the files

    - read_csv:
        fieldnames: color,size,price
        path: "{{ item }}"
      with_fileglob: fruits/*.csv
      register: fruit

Instead of creating the variables fruit_*, creating a dictionary of the fruits is simpler. For example, put the declarations below as appropriate

fruits: "{{ dict(f_keys | zip(f_vals)) }}"
f_vals: "{{ fruit.results | map(attribute='list') | list }}"
f_keys: "{{ fruit.results | map(attribute='item')
                          | map('basename')
                          | map('splitext')
                          | map('first') | list }}"

gives

fruits:
  apples:
    - {color: red, price: '20', size: big}
    - {color: green, price: '10', size: small}
  grapes:
    - {color: red, price: '20', size: big}
    - {color: black, price: '10', size: small}
  pears:
    - {color: green, price: '30', size: big}
    - {color: yellow, price: '20', size: small}

Example of a complete playbook

- hosts: localhost

  vars:

    fruits: "{{ dict(f_keys | zip(f_vals)) }}"
    f_vals: "{{ fruit.results | map(attribute='list') | list }}"
    f_keys: "{{ fruit.results | map(attribute='item')
                              | map('basename')
                              | map('splitext')
                              | map('first') | list }}"

  tasks:

    - read_csv:
        fieldnames: color,size,price
        path: "{{ item }}"
      with_fileglob: fruits/*.csv
      register: fruit

    - debug:
        var: fruits

    - debug:
        var: fruits.apples
Sign up to request clarification or add additional context in comments.

1 Comment

as always.. Wow by your approach and answer!! accepted
1

This will not be possible. According Registering variables

" When you register a variable in a task with a loop, the registered variable contains a value for each item in the loop. The data structure placed in the variable during the loop will contain a results attribute, that is a list of all responses from the module."

Therefore you need to extract the parts which you are interested in within the next tasks.

To get a better understanding in the behavior I've created a small test

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - name: Create multiple results and register them
    debug:
      msg: "{{ item }}"
    loop: [A, B, C]
    register: result

  - name: Show result
    debug:
      msg: "{{ result }}"

which is showing an equivalent behavior since with_fileglob is a with_X style loop.

TASK [Create multiple results and register them] ***
ok: [localhost] => (item=A) =>
  msg: A
ok: [localhost] => (item=B) =>
  msg: B
ok: [localhost] => (item=C) =>
  msg: C

TASK [Show result] *********************************
ok: [localhost] =>
  msg:
    changed: false
    msg: All items completed
    results:
    - ansible_loop_var: item
      changed: false
      failed: false
      item: A
      msg: A
    - ansible_loop_var: item
      changed: false
      failed: false
      item: B
      msg: B
    - ansible_loop_var: item
      changed: false
      failed: false
      item: C
      msg: C

Further Q&A

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.