5

Как присвоить значение heredoc переменной в Bash?

11

У меня есть многострочная строка (включая кавычки):

abc'asdf"
$(dont-execute-this)
foo"bar"''

Как я могу присвоить её переменной, используя heredoc в Bash?

Мне нужно сохранить переводы строк.

Я не хочу экранировать символы в строке, это было бы неудобно...

5 ответ(ов)

7

Вы можете избежать бесполезного использования cat и лучше обработать несовпадающие кавычки с помощью следующего:

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

Если вы не заключите переменную в кавычки при использовании echo, новые строки будут потеряны. Кавычки помогают сохранить их:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

Если вы хотите использовать отступы для лучшей читабельности в исходном коде, добавьте дефис после знаков меньше. Отступы должны быть выполнены только с помощью табуляций (без пробелов).

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

Если же вы хотите сохранить табуляции в содержимом результирующей переменной, вам нужно исключить табуляцию из IFS. Маркер терминала для here document (EOF) не должен иметь отступов.

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

Табуляции можно вставить в командной строке, нажав клавишу Tab. Если вы используете редактор, в зависимости от него это может работать или вам, возможно, придется отключить функцию, которая автоматически преобразует табуляции в пробелы.

В команде read -r -d '' параметры следующие:

  • -r позволяет воспринимать обратные косые черты буквально вместо использования их для экранирования символов.
  • -d устанавливает первый символ следующего аргумента в качестве разделителя между записями (строками), вместо стандартного, которым является новая строка. В примере я устанавливаю разделитель как пустую строку, так что вся строка, переданная в read, будет прочитана как одна запись.
4

Чтобы присвоить вывод команды cat вашей переменной, используйте $() следующим образом:

VAR=$(
cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)

# этот командный вывод продублирует переменную с сохранением новых строк
echo "$VAR"
# этот командный вывод устранит новые строки (заменив их на пробелы)
echo $VAR

Обратите внимание, что необходимо начинать имя END_HEREDOC с одинарных кавычек. Это предотвратит расширение содержимого heredoc, в результате чего dont-execute-this не будет выполнена.

Также стоит отметить, что разделитель окончательного heredoc END_HEREDOC должен находиться один на строке (поэтому скобка ) будет на следующей строке).

Спасибо за ответ @ephemient.

1

Это вариация метода Денниса, выглядит более элегантно в скриптах.

Определение функции (версия для bash):

define(){ IFS=$'\n' read -r -d '' ${1} || true; }

Использование:

define VAR <<'EOF'
abc 'asdf " \$ $ \n $'\n'
$(dont-exec ute-this)
foo " bar " ' ' 

`bad bad ``
EOF

echo "$VAR"

Обновленная версия ksh с использованием цикла read (также работает в bash):

function define { typeset a o=; while IFS= read -r a; do o+="$a"$'\n'; done; o=${o%?}; eval "$1=\$o"; }

Тесты (включают также версии, которые не удаляют последнюю новую строку): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c

Наслаждайтесь!

0

Ваша попытка использовать конструкцию VAR=<<END ... END не работает, потому что вы перенаправляете стандартный ввод на что-то, что этого не учитывает, а именно на оператор присваивания.

Использование конструкции с обратными кавычками делает это:

export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A

Однако это может вызвать некоторые проблемы, так как обратные кавычки могут помешать вам использовать это удобно. Лучше избегать использования обратных кавычек и вместо этого применять нотацию подстановки команд $(...).

Следующий пример работает корректно:

export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A

Таким образом, используйте $(...) для подстановки команд, это более современный и понятный подход.

0

Это не так - вы, вероятно, просто вводитесь в заблуждение поведением команды echo:

echo $VAR # удаляет переносы строк

echo "$VAR" # сохраняет переносы строк

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь