#bash #ansible #escaping #heredoc
#bash #ansible #экранирование #heredoc
Вопрос:
Я пытаюсь сгенерировать скрипт для копирования в ansible
ожидаемый / ответный блок с ssh
на удаленный хост. Я бы хотел избежать записи промежуточных файлов.
У меня две проблемы:
- Ansible, похоже, выполняет некоторую обработку,
command
которая портит многострочныеbash
сценарии, но я могу обойти это с помощью/bin/bash -c 'my multi line command'
(на фактических нескольких строках) - Кажется, я не могу правильно указать метку 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')", "", "admin@192.168.1.111's password: "]
И содержимое myscript.sh
либо неправильно оставлено в покое (т. Е. Все $...
развернуто), либо содержит последнее EOF
(поскольку оно не распознается как разделитель и просто считывается до конца командного блока, отсюда и предупреждение.
Каков правильный способ справиться с этим?
(Обратите внимание, что я делегирую localhost
, потому что я не хочу полагаться python
на целевой хост, это минимальные системы только с ssh
).
Комментарии:
1. Убедитесь, что отступ в
EOF
строке состоит только из символов ТАБУЛЯЦИИ, а не пробелов.2. Это было быстро 😉 К сожалению, это дает:
Syntax Error while loading YAML. found a tab character where an indentation space is expected
3. Если YAML не разрешает табуляции, вы не можете использовать маркер с отступом
EOF
.
Ответ №1:
Переместите закрывающий EOF влево на два пробела. На данный момент он не запускается в начале своей строки, поэтому bash не увидит его в качестве разделителя.
Со страницы руководства bash:
Здесь документы
Этот тип перенаправления предписывает оболочке считывать входные данные из текущего источника до тех пор, пока не будет видна строка, содержащая только разделитель (без конечных пробелов). Все строки, прочитанные до этого момента, затем используются в качестве стандартного ввода для команды. Формат here-documents является:
<<[-]word here-document delimiter
Не выполняется расширение параметров, подстановка команд, арифметическое расширение или расширение имени пути
включеноword
. Если какие-либо символы вword
заключены в кавычки,delimiter
является
результат удаления кавычек наword
и строки в here-document
не развернуты. Еслиword
не заключено в кавычки, все строки здесь-документа
подвергаются расширению параметров, замене команд и
арифметическое расширение. В последнем случае последовательность символов
<новая строка> игнорируется и должна использоваться для кавычек символов ,
$, и `. Если оператор перенаправления<<-
, то все ведущие вкладки
символы удаляются из строк ввода и строки, содержащей
delimiter
. Это позволяет here-документам в сценариях оболочки быть
отступ естественным образом.
Таким образом, вам нужно либо удалить отступ из EOF
строки, либо сделать отступ во всем с помощью табуляции вместо пробелов. Я полагаю, что первый вариант проще.
Комментарии:
1. «Два пробела превзойдены» в сочетании с двойными кавычками (т. Е.
<<-"EOF"
) сделали свое дело! (Одиночные кавычки распознаются как разделитель, но heredoc был непреднамеренно проанализирован.) Спасибо!2. Пока мы на этом: есть ли способ выполнить многострочный ввод
command: |
без необходимости дополнительногоbash
вызова?3. Я подозреваю, что использование одинарных кавычек могло быть потеряно, потому что вся ваша строка была в одинарных кавычках, но я не могу сказать наверняка.
4. Вы могли бы написать свой сценарий оболочки в одной строке (разделяя команды с
;
), хотя это, вероятно, просто означало бы, что вы отбросилиbash
в начале команды и вставили ее в качестве аргументаssh
.