9

So I know I can do something like this:

copy:
  dest: /etc/issue
  content: |
    Hello
    World

But this doesn't work:

vars:
  login_banner_text: !!str |-
    "Hello\nWorld"
tasks:
  - name: Set TTY login banner
    copy:
      dest: /etc/issue
      content: "{{ login_banner_text }}"

The newline character is printed straight to the file, without parsing, i.e. it's a single line populated with \n strings. I'd like to do this without copying a file into place, because I need to copy this text to two files.

For one file, the \n strings need to remain unparsed, so it's written to file as a single line. For the other, I want the \n to be interpreted, so that the text is expanded into multiple lines.

The first file is being modified using the ini_file module. This task works as expected using the explicit \n in the variable declaration.

- name: "Set message"
  ini_file:
    dest: /etc/dconf/db/gdm.d/00-security-settings
    section: org/gnome/login-screen
    option: banner-message-text
    value: string '{{ login_banner_text }}'
    create: yes
    tags:
      - always

However, other modules behave this way as well.

If I copy a file into place, the rather long text (not "Hello World") has to be maintained in two places.

Update

I found, what I think is, a better way of doing this, based on this post. It stores the banner in a separate file, and then uses that to modify both configuration files. So the value is only stored in one place. However, the answer given by @larsks does answer the question as it was originally posed.

- hosts: 127.0.0.1
  connection: local
  vars:
    login_banner_text: "{{ lookup('file', 'login_banner.txt') }}"
  tasks:
    - name: "Set the GNOME3 Login Warning Banner Text"
      ini_file:
        dest: /etc/dconf/db/gdm.d/00-security-settings
        section: org/gnome/login-screen
        option: banner-message-text
        value: '{{ login_banner_text | to_json }}'
        create: yes
      tags:
        - always
    - name: "Set the TTY Login Warning Banner Text"
      copy:
        dest: '/etc/issue'
        content: "{{ '\n' + login_banner_text + '\n' }}"
      tags:
        - always
orodbhen
  • 2,644
  • 3
  • 20
  • 29
  • I'm not clear what the problem is here: your first example does what you want. Why can't you just do it that way? – larsks Apr 05 '19 at 18:18
  • Because it needs to be stored as a variable with literal newlines. – orodbhen Apr 05 '19 at 18:35
  • You can use the same syntax you're using for `content:` in your first example to set the value of the variable. – larsks Apr 05 '19 at 18:46

1 Answers1

13

You already know how to specify a value with literal newlines; you're doing it when setting the content key in your first example. You can set the value of a variable the same way:

---
- hosts: localhost
  gather_facts: false
  vars:
    mytext: |
      Hello
      World
  tasks:
    - copy:
        dest: ./output.txt
        content: "{{ mytext }}"

This would create output.txt with the content:

Hello
World

If instead your goal is to have content like this...

[org/gnome/login-screen]

banner-message-text = "Hello\nWorld"

...then you don't want literal newlines, you want a literal \n, in which case this would work:

---
- hosts: localhost
  gather_facts: false
  vars:
    mytext: "Hello\\nWorld"

  tasks:
    - ini_file:
        dest: ./example.ini
        section: org/gnome/login-screen
        option: banner-message-text
        value: "{{ mytext }}"
        create: true

Which would result in:

[org/gnome/login-screen]
banner-message-text = Hello\nWorld

If you wanted the value in the config file quoted, then:

    - ini_file:
        dest: ./example.ini
        section: org/gnome/login-screen
        option: banner-message-text
        value: '"{{ mytext }}"'
        create: true

Which gets you:

[org/gnome/login-screen]
banner-message-text = "Hello\nWorld"

You could also do it like this:

---
- hosts: localhost
  gather_facts: false
  vars:
    mytext: |-
      Hello
      World

  tasks:
    - ini_file:
        dest: ./example.ini
        section: org/gnome/login-screen
        option: banner-message-text
        value: '{{ mytext|to_json }}'
        create: true

This gets you the same output as the previous example.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • That doesn't work the same way. If I try to output that variable to the other file, where the newline characters need to be preserved, it writes it as multiple lines. – orodbhen Apr 05 '19 at 18:54
  • That is literally what "literal newlines" means. It means include the actual newline characters, so you will of course get multiple lines. Is that **not** what you are trying to do? Can you update your question to show explicitly what output you expect in the target file? – larsks Apr 05 '19 at 18:57
  • By literal I mean not parsed or interpreted. The string is preserved in its original form. I'll update the question to clarify. – orodbhen Apr 05 '19 at 19:08
  • I've added a few alternatives. – larsks Apr 05 '19 at 19:16
  • Thanks. Is there a way to parse the `\n` strings when outputting to the ordinary text file? Using the YAML multi-line operator works, but in some places I need multiple newlines, so I'd rather not do it that way. It makes the playbook look messy, and causes problems with the syntax highlighting in the editor. – orodbhen Apr 08 '19 at 12:40
  • If you have literal `\n`s in your string, you could write out `{{ myvar.replace('\\n', '\n') }}`. – larsks Apr 08 '19 at 13:14
  • Possibly, this will help to anybody: https://yaml-multiline.info/ – fireman777 Mar 30 '21 at 21:24