Я хочу сгенерировать некоторый контент, используя heredoc в качестве шаблона:
passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
и передать его по трубопроводу oc create -f -
.
Если я добавлю вертикальную черту после EOF
, это не сработает.
Как передать heredoc с заменой переменных в то, что его потребляет?
решение1
Сначала вам нужно заключить в кавычки любую часть EOF
сразу после <<
. Самый естественный способ — <<"EOF"
, но <<E"OF"
или даже <<""EOF
подойдет. Без этого envsubst
получите строку с ${passphrase}
уже развернутой. Так как envsubst
работает со строками с литералом $foo
или ${foo}
подстроками, предварительное их развертывание означает envsubst
ничего не делает. Кроме того, в вашем случае оболочка, скорее всего, расширится ${passphrase}
до пустой строки, потому что определение переменной в вашем коде влияет только на envsubst
, а не на саму оболочку; если только переменная с тем же именем (случайно?) не установлена в оболочке заранее.
Теперь перейдем к вашему явному вопросу. Вы можете передать результат любой команде, но вам все равно нужно сохранить финальный EOF в отдельной строке. Один из способов сделать это так:
passphrase=$(<passphrase) envsubst <<"EOF" | oc create -f -
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
Или вы можете запустить код, который у вас есть, в подоболочке:
( passphrase=$(<passphrase) envsubst <<"EOF"
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
) | oc create -f -
ПримечаниеСправочное руководство по Bashговорит
Каждая команда в конвейере выполняется в своей собственной подоболочке.
поэтому даже в первом решении, когда нам удалось построить наш канал без ( )
, его первая часть (до |
) в любом случае выполняется в подоболочке. Второе решение делает эту подоболочку explicit. После того, как мы используем explicit (
, оболочка ждет explicit )
. Это позволяет нам разместить что-то после завершающего EOF
.
Удивительно, но даже с первым решением вы можете использовать более одного документа here ( <<
) в одной составной команде. Такие перенаправления не имеют особого смысла в конвейере, но они могут быть полезны с &&
и ||
.
command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF
То же самое, переставленное, с явными подоболочками:
( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF
В зависимости от ситуации вы можете предпочесть одну нотацию другой.
Возвращаясь к вашему конкретному примеру. С подоболочкой вам даже не нужно envsubst
:
( passphrase=$(<passphrase); oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
)
Между этим способом и двумя предыдущими есть интересные различия:
- На этот раз сама подоболочка должна расширяться
${passphrase}
, следовательно<<EOF
, нет<<"EOF"
. - Чтобы это работало, переменная должна быть известна подоболочке, а не только
oc
; это означает… passphrase=$(<passphrase) oc create -f - <<…
(обратите внимание на отсутствие точки с запятой) что это не сработает. - Технически тот же код не в подоболочке (т.е. без
( )
) также будет работать, но тогда переменная останется в основной оболочке. Запуск кода в подоболочке заставляет переменную умереть вместе с ним. В вашем исходном коде переменная не установлена для основной оболочки, так что я думаю, это то, что вам нужно.