Bash のプロセス置換と HERE ドキュメントを組み合わせるにはどうすればよいでしょうか?

Bash のプロセス置換と HERE ドキュメントを組み合わせるにはどうすればよいでしょうか?

Bash バージョン 4.2.47(1) リリースで、HERE ドキュメントから取得したフォーマットされたテキストを次のように連結しようとすると、

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.

次のエラーが発生します:

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
)

また、HERE ドキュメントを引用符で囲み、 write と書きたくありません<'FOOBAR'。これは、その中で変数を置換したいためです。

答え1

これは古い質問です。これは不自然な例であること (したがって、正しい解決策は を使用するcat |か、実際にはcatこの場合はまったく使用しないこと) がおわかりだと思いますので、一般的なケースに対する回答を投稿します。私はこれを関数に入れて、代わりにそれを使用することで解決します。

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
}

そしてそれを使って

cat <(fmt-func)

答え2

プロセス置換はこれとほぼ同等です。

例 - プロセス置換の仕組み

ステップ1 - FIFOを作成し、そこに出力する

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

ステップ2 - 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

HEREDOC 内での括弧の使用も問題ないようです。

例 - FIFO のみを使用する

ステップ1 - FIFOへの出力

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

ステップ2 - FIFOの内容を読み取る

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

あなたが遭遇している問題は、プロセス置換 が、<(...)その中の括弧のネストを考慮していないように見えることです。

例 - プロセスサブ + HEREDOC は機能しない

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

括弧を抜けば少しは緩和されるようです:

例 - 括弧のエスケープ

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

しかし、本当にあなたが望むものを得ることはできません。括弧のバランスをとることでも、それを和らげることができるようです。

例 - 括弧のバランス

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

Bash でこのような複雑な文字列を扱う必要があるときは、ほとんどの場合、最初に文字列を構築して変数に格納し、その後変数を介して使用します。最終的には脆弱になるような複雑なワンライナーを作成しようとするよりもです。

例 - 変数を使用する

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

それを印刷するには:

$ echo "$var"
(one)
(two

参考文献

答え3

これは単なる回避策です。プロセス置換を使用する代わりにパイプfmtを使用しますcat

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

関連情報