¿Cómo combinar la sustitución del proceso de Bash con el documento AQUÍ?

14

En la versión 4.2.47 (1) de Bash, suelte cuando intento catear texto formateado que proviene de un mensaje AQUÍ, así:

cat <(fmt --width=10 <<FOOBAR
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
) # I want this paranthesis to end the process substitution.

Obtuve el siguiente error:

bash: bad substitution: no closing `)' in <(fmt --width=10 <<FOOBAR
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
)

Además, no quiero citar el documento AQUÍ, es decir <'FOOBAR', escribir , porque todavía quiero que las variables se sustituyan dentro de él.

Tim Friske
fuente
¿Realmente necesitas la catllamada? ¿Por qué no dejarlo en la llamada fmt?
iruvar
2
Debo admitir que es un ejemplo artificial. Mis necesidades reales son más complejas que eso.
Tim Friske
1
Es interesante que cuando se reemplaza (Evencon la "(Even"que funciona. Es lo mismo para \(Even. Parece un error de análisis. Bash todavía está en un contexto en el que está buscando llaves, mientras que también está en el contexto de leer el documento aquí y ambos contextos se contradicen entre sí.
Raphael Ahrens
1
Esto se corrige en bash4.3, por cierto.
chepner

Respuestas:

7

La sustitución del proceso es más o menos equivalente a esto.

Ejemplo: mecánica de sustitución de procesos

Paso # 1 - haz un fifo, dale salida

$ mkfifo /var/tmp/fifo1
$ fmt --width=10 <<<"$(seq 10)" > /var/tmp/fifo1 &
[1] 5492

Paso # 2 - lee el fifo

$ cat /var/tmp/fifo1
1 2 3 4
5 6 7 8
9 10
[1]+  Done                    fmt --width=10 <<< "$(seq 10)" > /var/tmp/fifo1

El uso de parens dentro del HEREDOC también parece correcto:

Ejemplo: solo usando un FIFO

Paso # 1 - salida a FIFO

$ fmt --width=10 <<FOO > /var/tmp/fifo1 &
(one)
(two
FOO
[1] 10628

Paso # 2 - lee el contenido de FIFO

$ cat /var/tmp/fifo1
(one)
(two

El problema, creo que te estás encontrando es que la sustitución del proceso <(...)no parece importarle el anidamiento de los padres dentro de él.

Ejemplo: el proceso sub + HEREDOC no funciona

$ cat <(fmt --width=10 <<FOO
(one)
(two
FOO
)
bash: bad substitution: no closing `)' in <(fmt --width=10 <<FOO
(one)
(two
FOO
)
$

Escapar de los padres parece apaciguarlo un poco:

Ejemplo: escapar de los padres

$ cat <(fmt --width=10 <<FOO                 
\(one\)
\(two
FOO
)
\(one\)
\(two

Pero realmente no te da lo que quieres. Hacer que los padres estén equilibrados también parece calmarlo:

Ejemplo: equilibrio de parens

$ cat <(fmt --width=10 <<FOO
(one)
(two)
FOO
)
(one)
(two)

Cada vez que tengo cadenas complejas, como esta con las que lidiar en Bash, casi siempre las construyo primero, las almaceno en una variable y luego las uso a través de la variable, en lugar de intentar crear un forro complicado que termine siendo frágil.

Ejemplo: use una variable

$ var=$(fmt --width=10 <<FOO
(one)
(two
FOO
)

Luego para imprimirlo:

$ echo "$var"
(one)
(two

Referencias

slm
fuente
3

Esto es solo una solución alternativa. Tubería fmten catlugar de usar la sustitución del proceso

fmt --width=10 <<FOOBAR | cat 
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
iruvar
fuente
1
Intenté tu "solución" y funcionaría para mí. Gracias. Pero aún así quiero entender por qué mi combinación de un documento HERE anidado dentro de una sustitución de proceso no funciona. ¿Tienes una respuesta?
Tim Friske
@TimFriske, voy a tener que diferir a uno de los bashasistentes en este sitio. Mi conocimiento de los componentes internos de bash parser se limita, por decir lo menos
iruvar
2

Esta es una vieja pregunta, y cuando se dé cuenta de que este es un ejemplo artificial (y, por lo tanto, que la solución correcta es usar cat |o no, caten absoluto en este caso), simplemente publicaré mi respuesta para el caso general. Lo resolvería poniéndolo en una función y usándolo en su lugar.

fmt-func() {
    fmt --width=10 <<FOOBAR
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
}

y luego usar eso

cat <(fmt-func)
falstro
fuente
¡Gracias! Exactamente lo que estaba buscando.
piarston