Quiero generar contenido usando un heredoc como plantilla:
passphrase=$(<passphrase) envsubst <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
y canalícelo a oc create -f -
.
Si agrego una tubería después de EOF
, no funciona.
¿Cómo puedo canalizar un heredoc con sustitución de variables a algo que lo consume?
Respuesta1
Primero debe citar cualquier parte de EOF
justo después <<
. La forma más natural es <<"EOF"
, pero <<E"OF"
o incluso <<""EOF
servirá. Sin esto, envsubst
la cadena ${passphrase}
ya estará expandida. Dado que envsubst
opera en cadenas con literales $foo
o ${foo}
subcadenas, expandirlas de antemano significa que envsubst
no tiene nada que ver. Además, en su caso, lo más probable es que el shell se expanda ${passphrase}
a una cadena vacía, porque la definición de la variable en su código solo afecta a envsubst
, no al shell en sí; a menos que la variable con el mismo nombre esté (¿accidentalmente?) configurada en el shell de antemano.
Ahora llegamos a su pregunta explícita. Puede canalizar el resultado a cualquier comando que desee, pero aún así deberá mantener el EOF final en una línea separada. Una forma de hacerlo es así:
passphrase=$(<passphrase) envsubst <<"EOF" | oc create -f -
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
O puedes ejecutar el código que tienes en un subshell:
( passphrase=$(<passphrase) envsubst <<"EOF"
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
) | oc create -f -
NotaManual de referencia de bashdice
Cada comando en una canalización se ejecuta en su propia subcapa
Entonces, incluso en la primera solución, cuando logramos construir nuestra tubería sin ( )
, su primera parte (antes |
) se ejecuta en una subcapa de todos modos. La segunda solución hace explícita esta subcapa. Después de usar explícito (
, el shell espera explícito )
. Esto nos permite colocar algo después de la terminación EOF
.
Sorprendentemente, incluso con la primera solución puedes usar más de un documento aquí ( <<
) en un solo comando compuesto. Estas redirecciones tienen poco sentido en una tubería, pero pueden resultar útiles con &&
y ||
.
command1 <<EOF && command2 <<EOF || command3 <<EOF
content1
EOF
content2
EOF
content3
EOF
Lo mismo reordenado, con subcapas explícitas:
( command1 <<EOF
content1
EOF
) && ( command2 <<EOF
content2
EOF
) || command3 <<EOF
content3
EOF
Dependiendo de la situación, es posible que prefieras una notación sobre la otra.
Volvamos a su ejemplo específico. Con una subcapa ni siquiera necesitas envsubst
:
( passphrase=$(<passphrase); oc create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: openshift-passphrase
stringData:
passphrase: ${passphrase}
EOF
)
Existen diferencias interesantes entre esta forma y las dos anteriores:
- Esta vez la propia subcapa debería expandirse
${passphrase}
, por lo tanto<<EOF
, no<<"EOF"
. - Para que esto funcione, la variable debe ser conocida por el subshell, no sólo por
oc
; esto significa… passphrase=$(<passphrase) oc create -f - <<…
(tenga en cuenta la falta de punto y coma) no funcionaría. - Técnicamente, el mismo código que no esté en un subshell (es decir, sin
( )
) también funcionaría, pero entonces la variable permanecería en el shell principal. Ejecutar el código en una subcapa hace que la variable muera con él. En su código original, la variable no está configurada para el shell principal, así que supongo que esto es lo que desea.