¿Cómo puedo utilizar un "documento aquí" en medio de una tubería?

¿Cómo puedo utilizar un "documento aquí" en medio de una tubería?

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 EOFjusto después <<. La forma más natural es <<"EOF", pero <<E"OF"o incluso <<""EOFservirá. Sin esto, envsubstla cadena ${passphrase}ya estará expandida. Dado que envsubstopera en cadenas con literales $fooo ${foo}subcadenas, expandirlas de antemano significa que envsubstno 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.

información relacionada