Я хочу создать некоторый контент, используя heredoc в качестве шаблона:

passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: openshift-passphrase
stringData:
  passphrase: ${passphrase}
EOF

и передайте его в oc create -f - .

Если я добавлю трубу после EOF , это не сработает.

Как я могу передать heredoc с подстановкой переменных к тому, что потребляет это?

1 ответ1

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 Справочное руководство говорит

Каждая команда в конвейере выполняется в своей собственной оболочке

так что даже в первом решении, когда нам удалось построить нашу трубу без ( ) , его первая часть (перед | ) все равно работает в подоболочке. Второе решение делает эту подоболочку явной. После того, как мы используем явное ( оболочка ожидает явного ) . Это позволяет нам размещать что-то после завершающего EOF .

Удивительно, но даже с первым решением вы можете использовать более одного документа здесь (<<) в одной составной команде. Такие перенаправления не имеют большого смысла в трубе, но они могут быть полезны с && и || ,

command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF

То же переставил, с явными подоболочками:

( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF

В зависимости от ситуации вы можете предпочесть одну запись другим.

Вернемся к вашему конкретному примеру. С subshell вам даже не нужен 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 - <<… (обратите внимание на отсутствие точки с запятой) не будет работать.
  • Технически тот же код не в подоболочке (то есть без ( ) ) также будет работать, но тогда переменная останется в основной оболочке. Запуск кода в подоболочке заставляет переменную умереть вместе с ней. В вашем исходном коде переменная не установлена для основной оболочки, поэтому я думаю, это то, что вы хотите.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .