Comment combiner la substitution de processus de Bash avec HERE-document?

14

Dans la version 4.2.47 (1) de Bash, relâchez lorsque j'essaie de caténaliser du texte formaté qui provient d'un ICI-découment comme ceci:

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.

J'obtiens l'erreur suivante:

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
)

De plus, je ne veux pas citer le document ICI, c'est-à-dire écrire <'FOOBAR', car je veux toujours que des variables y soient substituées.

Tim Friske
la source
Avez-vous vraiment besoin de cet catappel? Pourquoi ne pas le laisser appeler fmt?
iruvar
2
Je dois admettre que c'est un exemple artificiel. Mes besoins réels sont plus complexes que cela.
Tim Friske
1
Il est intéressant de noter que lorsque vous remplacez (Evenavec "(Even"cela fonctionne. C'est pareil pour \(Even. On dirait un bug d'analyse. Bash est toujours dans un contexte où il cherche des accolades tout en étant également dans le contexte de la lecture du document ici et les deux contextes se contredisent.
Raphael Ahrens
1
Ceci est corrigé en bash4.3, soit dit en passant.
chepner

Réponses:

7

La substitution de processus est à peu près équivalente à cela.

Exemple - mécanique de substitution de processus

Étape # 1 - Créez un fifo, éditez-le

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

Étape # 2 - Lisez le 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

L'utilisation de parens au sein de l'HEREDOC semble également correcte:

Exemple - en utilisant simplement un FIFO

Étape # 1 - sortie vers FIFO

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

Étape # 2 - lire le contenu de FIFO

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

Le problème, je crois que vous vous heurtez, est que la substitution de processus <(...)ne semble pas se soucier de l'imbrication des parens en son sein.

Exemple - processus sub + HEREDOC ne fonctionne pas

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

Échapper aux parens semble l'apaiser un peu:

Exemple - échapper aux parens

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

Mais ne vous donne pas vraiment ce que vous voulez. Équilibrer les parens semble également l'apaiser:

Exemple - équilibrage des parens

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

Chaque fois que j'ai des chaînes complexes, comme celle-ci avec Bash, je les construirai presque toujours en premier, en les stockant dans une variable, puis en les utilisant via la variable, plutôt que d'essayer de créer une doublure délicate qui finira par être fragile.

Exemple - utilisez une variable

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

Puis pour l'imprimer:

$ echo "$var"
(one)
(two

Les références

slm
la source
3

Ceci est juste une solution de contournement. Diriger fmtvers catau lieu d'utiliser la substitution de processus

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
la source
1
J'ai essayé votre "solution de contournement" et cela fonctionnerait pour moi. Merci. Mais je veux quand même comprendre pourquoi ma combinaison d'un document ICI imbriqué dans une substitution de processus ne fonctionne pas. Avez-vous une réponse?
Tim Friske
@TimFriske, je vais devoir remettre celui-ci à l'un des bashassistants de ce site. Ma connaissance des internes de l'analyseur bash est pour le moins
limitée
2

Ceci est une vieille question, et comme vous vous rendez compte que c'est un exemple artificiel (et donc que la bonne solution est d'utiliser cat |ou en fait, aucuncat du tout dans ce cas), je vais simplement poster ma réponse pour le cas général. Je le résoudrais en le mettant dans une fonction et en l'utilisant à la place.

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
}

puis l'utiliser

cat <(fmt-func)
falstro
la source
Je vous remercie! Exactement ce que je cherchais.
piarston