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

14

В Bash версии 4.2.47 (1) -релиз, когда я пытаюсь наклеить отформатированный текст, полученный из 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', потому что я все еще хочу, чтобы в нем были подставлены переменные.

Тим Фриске
источник
Вам действительно нужен catзвонок? Почему бы не оставить это при звонке fmt?
Ирувар
2
Я должен признать, что это надуманный пример. Мои реальные потребности более сложны, чем это.
Тим Фриске
1
Интересно, что при замене (Evenна "(Even"это работает. Это то же самое для \(Even. Похоже, ошибка разбора. Bash все еще находится в контексте, где он ищет фигурные скобки, а также в контексте чтения документа здесь, и оба контекста противоречат друг другу.
Рафаэль Аренс
1
Это исправлено в bash4.3, кстати.
chepner

Ответы:

7

Процесс замещения примерно эквивалентен этому.

Пример - механика процесса замещения

Шаг № 1 - сделать фифо, вывести на него

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

Шаг № 2 - читать Фио

$ 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

Ссылки

SLM
источник
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
Iruvar
источник
1
Я попробовал ваш «обходной путь», и он сработал бы для меня. Благодарю. Но все же я хочу понять, почему моя комбинация HERE-документа, вложенного в подстановку процесса, не работает. У тебя есть ответ?
Тим Фриске
@TimFriske, мне придется отложить это до одного из bashволшебников на этом сайте. Мои знания внутренних компонентов bash parser ограничены,
мягко
2

Это старый вопрос, и, поскольку вы понимаете, что это надуманный пример (и, следовательно, правильное решение - использовать 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)
falstro
источник
Спасибо! Именно то, что я искал.
пиарстон