Как присвоить значение heredoc переменной в Bash?
У меня есть многострочная строка (включая кавычки):
abc'asdf"
$(dont-execute-this)
foo"bar"''
Как назначить его переменной с помощью heredoc в Bash?
Мне нужно сохранить символы новой строки.
Я не хочу скрывать символы в строке, что было бы неприятно...
Ответы
Ответ 1
Вы можете избежать бесполезного использования cat
и справиться с несогласованными кавычками с этим:
$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
Если вы не цитируете эту переменную, когда вы ее эхо, новые строки теряются. Цитируя его, они сохраняют их:
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
Если вы хотите использовать отступы для чтения в исходном коде, используйте тире после менее-thans. Отступ должен выполняться с использованием только вкладок (без пробелов).
$ read -r -d '' VAR <<-'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
Если вместо этого вы хотите сохранить вкладки в содержимом результирующей переменной, вам нужно удалить вкладку из IFS
. Маркер терминала для этого документа (EOF
) не должен иметь отступ.
$ IFS='' read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
Вкладки можно вставить в командной строке, нажав Ctrl - V Tab. Если вы используете редактор, в зависимости от того, какой из них может работать, или вам может потребоваться отключить функцию, которая автоматически преобразует вкладки в пробелы.
Ответ 2
Используйте $() для назначения вывода cat
вашей переменной следующим образом:
VAR=$(cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)
echo "$VAR"
Обязательно разделите END_HEREDOC на одиночные кавычки.
Благодаря @ephemient
для ответа.
Ответ 3
это вариация метода Денниса, выглядит более элегантно в сценариях.
определение функции:
define(){ IFS='\n' read -r -d '' ${1} || true; }
использование:
define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
echo "$VAR"
пользоваться
p.s. сделал версию "read loop" для оболочек, которые не поддерживают read -d
. должен работать с set -eu
и неспаренными backticks, но не очень хорошо тестировался:
define(){ o=; while IFS="\n" read -r a; do o="$o$a"'
'; done; eval "$1=\$o"; }
Ответ 4
VAR=<<END
abc
END
не работает, потому что вы перенаправляете stdin на то, что ему неинтересно, а именно: назначение
export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A
работает, но там есть обратная связь, которая может помешать вам использовать это. Кроме того, вам действительно следует избегать использования обратных ссылок, лучше использовать нотацию замещения команды $(..)
.
export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A
Ответ 5
Добавление комментария здесь как ответ, так как у меня недостаточно комментариев, чтобы прокомментировать ваш текст вопроса.
По-прежнему нет решения, которое сохраняет символы новой строки.
Это неверно - вы, вероятно, просто вводите в заблуждение поведение эха:
echo $VAR # strips newlines
echo "$VAR" # preserves newlines
Ответ 6
Массив - это переменная, поэтому в этом случае mapfile будет работать
mapfile y <<z
abc'asdf"
$(dont-execute-this)
foo"bar"''
z
Затем вы можете печатать как это
printf %s "${y[@]}"
Ответ 7
присваивать значение heredoc переменной
VAR="$(cat <<'VAREOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
VAREOF
)"
используется как аргумент команды
echo "$(cat <<'SQLEOF'
xxx''xxx'xxx'xx 123123 123123
abc'asdf"
$(dont-execute-this)
foo"bar"''
SQLEOF
)"
Ответ 8
Включение ветки Ответ Neil, вам часто не нужен var вообще, вы можете использовать функцию почти так же, как переменную, и это намного проще для чтения, чем встроенные или read
решения.
$ complex_message() {
cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}
$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''
Ответ 9
Мне показалось, что я должен прочитать строку с NULL в ней, так что вот решение, которое будет читать все, что вы бросаете на него. Хотя, если вы действительно имеете дело с NULL, вам нужно будет справиться с этим на уровне шестнадцатеричного.
$cat > read.dd.sh
read.dd() {
buf=
while read; do
buf+=$REPLY
done < <( dd bs=1 2>/dev/null | xxd -p )
printf -v REPLY '%b' $( sed 's/../ \\\x&/g' <<< $buf )
}
Доказательство:
$ . read.dd.sh
$ read.dd < read.dd.sh
$ echo -n "$REPLY" > read.dd.sh.copy
$ diff read.dd.sh read.dd.sh.copy || echo "File are different"
$
Пример HEREDOC (с ^ J, ^ M, ^ I):
$ read.dd <<'HEREDOC'
> (TAB)
> (SPACES)
(^J)^M(^M)
> DONE
>
> HEREDOC
$ declare -p REPLY
declare -- REPLY=" (TAB)
(SPACES)
(^M)
DONE
"
$ declare -p REPLY | xxd
0000000: 6465 636c 6172 6520 2d2d 2052 4550 4c59 declare -- REPLY
0000010: 3d22 0928 5441 4229 0a20 2020 2020 2028 =".(TAB). (
0000020: 5350 4143 4553 290a 285e 4a29 0d28 5e4d SPACES).(^J).(^M
0000030: 290a 444f 4e45 0a0a 220a ).DONE
Ответ 10
Благодаря dimo414 answer, это показывает, как работает его отличное решение, и показывает, что вы также можете легко использовать цитаты и переменные в тексте:
Пример вывода
$ ./test.sh
The text from the example function is:
Welcome dev: Would you "like" to know how many 'files' there are in /tmp?
There are " 38" files in /tmp, according to the "wc" command
test.sh
#!/bin/bash
function text1()
{
COUNT=$(\ls /tmp | wc -l)
cat <<EOF
$1 Would you "like" to know how many 'files' there are in /tmp?
There are "$COUNT" files in /tmp, according to the "wc" command
EOF
}
function main()
{
OUT=$(text1 "Welcome dev:")
echo "The text from the example function is: $OUT"
}
main
Ответ 11
$TEST="ok"
read MYTEXT <<EOT
this bash trick
should preserve
newlines $TEST
long live perl
EOT
echo -e $MYTEXT