Как объединить подстановку процессов Bash с HERE-документом?

Как объединить подстановку процессов Bash с HERE-документом?

В Bash версии 4.2.47(1)-release при попытке объединить форматированный текст, полученный из HERE-dcoument, следующим образом:

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-документ, т.е. писать <'FOOBAR', потому что я все равно хочу, чтобы в нем были подставлены переменные.

решение1

Это старый вопрос, и как вы понимаете, это надуманный пример (и, таким образом, правильным решением будет использовать cat |or, на самом деле, 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

Проблема, с которой, как я полагаю, вы столкнулись, заключается в том, что процесс подстановки, <(...)похоже, не учитывает вложенность скобок внутри него.

Пример - процесс sub + 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

Связанный контент