Как внести текст HEREDOC в переменную сценария оболочки?

Вам не нужно редактировать ваш ~ / .zshrc .

Поскольку вы работаете с virtualenvwrapper , можно добавить параметры или перехватчики в $ WORKON_HOME / post (de) activate файлы.

Если вы хотите увидеть более подробную информацию, обратитесь к здесь .

Приведенная выше ссылка позволяет мне сделать следующее:

В моем случае $ WORKON_HOME = ~ / Envs , потому что я изменил этот путь при установке virtualenvwrapper; в противном случае у вас должна быть папка ~ / .virtualenvs .

  1. Откройте файл postactivate , расположенный в $ WORKON_HOME

  2. Добавьте эти строки:

     PS1 = "$ _ OLD_VIRTUAL_PS1" 
     _ OLD_RPROMPT = "$ RPROMPT" {{1 }} RPROMPT = "% {$ {fg_bold [белый]}%} (env:% {$ {fg [green]}%}` basename \ "$ VIRTUAL_ENV \" `% {$ {fg_bold [white]}%} )% {$ {reset_color}%} $ RPROMPT "
     
  3. Сохраните и наслаждайтесь!

    Вы получите что-то вроде этого: done

  4. (НЕОБЯЗАТЕЛЬНО) Если хотите, вы можете отредактировать файл postdeactivate , добавив эту строку:

     RPROMPT = "$ _ OLD_RPROMPT" 
     

9
29.01.2017, 05:38
4 ответа

Проблема в том, что в Bash внутри $ (...) escape-последовательностей (и других) разбираются, даже если сам heredoc их не имеет. Вы получаете удвоенную строку, потому что \ экранирует разрыв строки. То, что вы видите, на самом деле является проблемой синтаксического анализа в Bash - другие оболочки этого не делают. Обратные кавычки также могут быть проблемой в старых версиях. Я подтвердил, что это ошибка в Bash , и она будет исправлена ​​в будущих версиях.

Вы можете, по крайней мере, значительно упростить вашу функцию:

func() {
    res=$(cat)
}
func <<'HEREDOC'
...
HEREDOC

Если вы хотите выбрать выходную переменную, ее можно параметризовать:

func() {
    eval "$1"'=$(cat)'
}
func res<<'HEREDOC'
...
HEREDOC

Или довольно некрасивую без eval :

{ res=$(cat) ; } <<'HEREDOC'
...
HEREDOC

Параметр {} необходимы, а не () , чтобы переменная оставалась доступной впоследствии.

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


Если вы можете использовать zsh , ваша исходная подстановка команд + heredoc будет работать как есть, но вы также можете свернуть все это дальше:

x=$(<<'EOT'
...
EOT
)

Bash не поддерживает это и я не думаю, что какая-либо другая оболочка, которая столкнется с вашей проблемой, тоже.

15
27.01.2020, 20:05

О решении OP:

  • Вам не нужен eval для присвоения переменной, если вы разрешаете использовать некоторую постоянную переменную.

  • Также может быть реализована общая структура вызова функции, которая принимает HEREDOC.

Решение, которое работает во всех (разумных) оболочках, когда оба пункта решены, следующее:

#!/bin/bash
nl="
"

read_heredoc(){
    var=""
    while IFS="$nl" read -r line; do
        var="$var$line$nl"
    done 
}


read_heredoc <<'HEREDOC'

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |
            |___/|_|

HEREDOC

read_heredoc2_result="$str"

printf '%s' "${read_heredoc2_result}"

Решение исходного вопроса.

Решение, работающее с bash 2.04 (и недавних версий zsh, lksh, mksh).
Ниже вы найдете более портативную (POSIX) версию.

#!/bin/bash
read_heredoc() {
    IFS='' read -d '' -r var <<'HEREDOC'

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |
            |___/|_|



HEREDOC

}

read_heredoc
echo "$var"

Основная команда

IFS='' read -d '' -r var <<'HEREDOC'

работает следующим образом:

  1. Слово HEREDOC заключено в (одинарные) кавычки, чтобы избежать расширения текста, который следует за ним.
  2. Содержимое «здесь, документ» подается в стандартный ввод с помощью << .
  3. Параметр -d '' заставляет читать , чтобы пропустить все содержимое «здесь документа».
  4. Параметр -r позволяет избежать интерпретации символов в кавычках с обратной косой чертой.
  5. Основная команда аналогична команде read var .
  6. И последняя деталь - IFS = '' , что позволит избежать чтения и удаления начальных или конечных символов в IFS по умолчанию: пробел табуляция новая строка .

В ksh нулевое значение параметра -d '' не работает.
В качестве временного решения, если в тексте нет «возврата каретки», работает -d $ '\ r' (если $ '\ r' , конечно же, добавляется в конец каждой строки).


Дополнительное (в комментариях) требование - создать решение, совместимое с POSIX.

POSIX

Расширение идеи, позволяющей запускать только с параметрами POSIX.
В основном это означает отсутствие -d для чтения . Это заставляет читать каждую строку.
Это, в свою очередь, вызывает необходимость захватывать по очереди.
Затем для построения var необходимо добавить завершающую новую строку (поскольку чтение удалило ее).

#!/bin/sh

nl='
'

read_heredoc() {
    unset var
    while IFS="$nl" read -r line; do
        var="$var$line$nl"
    done <<\HEREDOC

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \ 
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/ 
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___| 
             __/ | | 
            |___/|_| 



HEREDOC

}

read_heredoc
printf '%s' "$var"

Это работает (и было протестировано) во всех разумных оболочках.

6
27.01.2020, 20:05

Чтобы поддерживать завершающие символы новой строки, я объединил ответ от @MichaelHomer и свое исходное решение. Я не использовал предлагаемые обходные пути из ссылки, которую отметил @EliahKagan, потому что первая использует магические строки, а последние две не соответствуют POSIX.

#!/bin/sh

NEWLINE="
"

read_heredoc() {
  read_heredoc_result=""
  while IFS="${NEWLINE}" read -r read_heredoc_line; do
    read_heredoc_result="${read_heredoc_result}${read_heredoc_line}${NEWLINE}"
  done
  eval $1'=${read_heredoc_result}'
}

read_heredoc heredoc_str <<'HEREDOC'

                        _                            _ _
                       | |                          | (_)
  _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | |_ _ __   ___
 | '_ ` _ \| | | | '_ \| |/ _` |/ __/ _ \/ _ \| '_ \| | | '_ \ / _ \
 | | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
 |_| |_| |_|\__, | .__/|_|\__,_|\___\___|\___/|_| |_|_|_|_| |_|\___|
             __/ | |
            |___/|_|




HEREDOC

echo "${heredoc_str}"
2
27.01.2020, 20:05

Бесполезное использование cat (цитата \ и `):

myplaceonline="
                       _                            _ _            
 _ __ ___  _   _ _ __ | | __ _  ___ ___  ___  _ __ | (_)_ __   ___ 
| '_ \` _ \\| | | | '_ \\| |/ _\` |/ __/ _ \\/ _ \\| '_ \\| | | '_ \\ / _ \\
| | | | | | |_| | |_) | | (_| | (_|  __/ (_) | | | | | | | | |  __/
|_| |_| |_|\\__, | .__/|_|\\__,_|\\___\\___|\\___/|_| |_|_|_|_| |_|\\___|
       |___/|_
"

Или без цитирования:

myplaceonline="$(figlet myplaceonline)"
2
27.01.2020, 20:05

Теги

Похожие вопросы