Ansible цитирует heredoc в ожидаемом/командном блоке, не находя разделителя/многострочную команду в ожидаемой команде

Я пытаюсь создать сценарий для копирования в блоке ожидания/ответа ansible с ssh на удаленный хост. Я бы хотел избежать написания промежуточных файлов.

У меня есть две проблемы:

  1. Ansible, кажется, выполняет некоторую обработку в command, которая портит многострочные сценарии bash, но я могу обойти это с помощью /bin/bash -c 'my \ multi \ line \ command' (на самом деле несколько строк)
  2. Кажется, я не могу правильно указать метку EOF для heredoc внутри вызова bash (см. ниже)
  - name: Generate script on the fly
    expect: 
      command: |
        /bin/bash -c 'ssh -o PubkeyAuthentication=no -p {{ ansible_ssh_port }} {{ ansible_user }}@{{ ansible_host }} "cat - > {{ tgtdir }}/myscript.sh" <<-'EOF' 
          #! /bin/env sh
          a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; THIS=$(cd "$a"; pwd)
          echo "Script dir == ${THIS}"
          echo "{{ someansiblevar }}"
          EOF
        '
      responses:
        (.*)password: "{{ ansible_ssh_pass }}"
    delegate_to: localhost

(Обратите внимание, что в этом примере я, по-видимому, избегаю использования одинарных кавычек внутри одинарных кавычек, но все другие варианты также терпят неудачу.)

Я пытался избежать кавычек вокруг первого EOF разными способами, но всегда получаю предупреждение:

"stdout_lines": ["/bin/bash: line 10: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')", "", "[email protected]'s password: "]

А содержимое myscript.sh либо не корректно оставлено (т.е. все $... развернуто), либо содержит последнее EOF (поскольку оно не распознается как разделитель и просто читается до конца командного блока, отсюда и предупреждение.

Каков правильный способ справиться с этим?

(Обратите внимание, что я делегирую localhost, потому что не хочу полагаться на python на целевом хосте, это минимальные системы только с ssh).


person ppenguin    schedule 08.09.2020    source источник
comment
Убедитесь, что отступ в строке EOF состоит только из символов TAB, а не из пробелов.   -  person Barmar    schedule 08.09.2020
comment
Это было быстро;) К сожалению, это дает: Syntax Error while loading YAML. found a tab character where an indentation space is expected   -  person ppenguin    schedule 09.09.2020
comment
Если YAML не поддерживает вкладки, вы не можете использовать токен EOF с отступом.   -  person Barmar    schedule 09.09.2020


Ответы (1)


Переместите закрывающий EOF влево на два пробела. На данный момент он не начинается в начале своей строки, поэтому bash не увидит его как разделитель.

С справочной страницы bash:

Здесь Документы

Этот тип перенаправления указывает оболочке читать ввод из текущего источника до тех пор, пока не будет видна строка, содержащая только разделитель (без пробелов в конце). Все строки, прочитанные до этого момента, затем используются в качестве стандартного ввода для команды. Формат здесь-документов:

<<[-]word
        here-document 
delimiter 

Для word не выполняется расширение параметров, подстановка команд, арифметическое расширение или расширение имени пути. Если какие-либо символы в word заключены в кавычки, delimiter является результатом удаления кавычек в word, а строки в здесь-документе не расширяются. Если word не заключен в кавычки, все строки здесь-документа подвергаются расширению параметров, подстановке команд и арифметическому расширению. В последнем случае последовательность символов \‹новая строка› игнорируется, и \ должен использоваться для заключения символов \, $ и ` в кавычки. Если оператор перенаправления — <<-, то все начальные символы табуляции удаляются из входных строк и строки, содержащей delimiter. Это позволяет размещать здесь-документы в сценариях оболочки естественным образом.

Таким образом, вам нужно будет либо удалить отступ из строки EOF, либо сделать отступ с помощью табуляции вместо пробелов. Я полагаю, что первый вариант проще.

person lxop    schedule 08.09.2020
comment
Два пробела в сочетании с двойными кавычками (например, <<-"EOF") сделали свое дело! (Одинарные кавычки были распознаны как разделитель, но heredoc был случайно проанализирован.) Спасибо! - person ppenguin; 09.09.2020
comment
Пока мы в этом: есть ли способ сделать многострочный в command: | без необходимости дополнительного вызова bash? - person ppenguin; 09.09.2020
comment
Я подозреваю, что использование одинарных кавычек могло быть потеряно, потому что вся ваша строка была заключена в одинарные кавычки, но я не могу сказать наверняка. - person lxop; 09.09.2020
comment
Вы можете написать свой сценарий оболочки в одной строке (разделяя команды с помощью ;), хотя это, вероятно, будет просто означать, что вы уберете bash в начале команды и вставите его в качестве аргумента для ssh. - person lxop; 09.09.2020