linuxsedansible

'sed' command returns 'No such file or directory' when ran with ansible script?


I have a command in my ansible script that replaces a line in a file. The command works just fine when ran on my machine. However, when it's ran with my ansible script, it says No such file or directory. The thing is, the file DOES exist and 'sed' DID replace that line. So the command did run successfully, but it's still gave me an error? Anyone know what might be causing this?

Ansible task

- name: Update path in plotly package
  become: true 
  shell: 
    cmd: 
    sed -e '2s/.*/DIR="$( cd "$( \/usr\/bin\/dirname "${BASH_SOURCE[0]}" )" >\/dev\/null 2>\&1 \&\& pwd )"/' -i '' /plotly/app/venv/lib64/python3.9/site-packages/kaleido/executable/kaleido

Error

TASK [packages/plotly : Replace line in plotly package] ********************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "sed -e '2s/.*/DIR=\"$( cd \"$( \\/usr\\/bin\\/dirname \"${BASH_SOURCE[0]}\" )\" >\\/dev\\/null 2>\\&1 \\&\\& pwd )\"/' -i '' /plotly/app/venv/lib64/python3.9/site-packages/kaleido/executable/kaleido", "delta": "0:00:00.004789", "end": "2024-07-30 16:16:24.704142", "msg": "non-zero return code", "rc": 2, "start": "2024-07-30 16:16:24.699353", "stderr": "sed: can't read : No such file or directory", "stderr_lines": ["sed: can't read : No such file or directory"], "stdout": "", "stdout_lines": []}

Solution

  • For your Use Case it is recommended to use the lineinfile module – Manage lines in text files instead, even ini_file module – Tweak settings in INI files might be feasible. A specific Ansible module is usually less error prone, has better abstraction and error handling, supports check_mode, diff mode, changed, has safe_file_operations, can ensure idempotence, and many reasons more ...


    Anyways, on a RHEL-system, for a test file like

    - This
    - is
    - a
    - test.
    

    a less recommended minimal example playbook

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      tasks:
    
      - shell:
          cmd: |
            sed --in-place '/ is/{
            s// was/g
            w /dev/stdout
            }' /home/ansible/test.txt
        register: result
        changed_when: result.stdout_lines | length | int > 0
    
      - debug:
          var: result
    

    will result into an output of

    TASK [shell] **********************************
    changed: [localhost]
    
    TASK [debug] **********************************
    ok: [localhost] =>
      result:
        changed: true
        cmd: |-
          sed --in-place '/ is/{
          s// was/g
          w /dev/stdout
          }' /home/ansible_user/test.txt
        delta: '0:00:00.006268'
        end: '2024-07-31 11:00:00.648871'
        failed: false
        msg: ''
        rc: 0
        start: '2024-07-31 11:00:00.642603'
        stderr: ''
        stderr_lines: []
        stdout: '- was'
        stdout_lines:
        - '- was'
    
    PLAY RECAP ***********************************
    localhost                  : ok=2    changed=1
    

    and a changed file of

    - This
    - was
    - a
    - test.
    

    The second run would result into

    TASK [shell] *********************************
    ok: [localhost]
    
    TASK [debug] *********************************
    ok: [localhost] =>
      result:
        changed: false
    ...
    
    PLAY RECAP ***********************************
    localhost                  : ok=2    changed=0
    

    Further Reading

    As one probably also need to think about How to report sed --in-place changes?, as well How to print line numbers changed by sed?