Как присвоить значение heredoc переменной в Bash?
У меня есть эта многострочная строка (включая кавычки):
abc'asdf"
$(dont-execute-this)
foo"bar"''
Как бы я назначил его переменной, используя heredoc в Bash?
мне нужно сохранить новые строки.
Я не хочу, чтобы избежать символов в строке, что было бы раздражает...
11 ответов:
вы можете избежать бесполезного использования
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
. Маркер терминала для here doc (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 -VTab. Если вы используете редактор, в зависимости от того, какой из них, это также может работать, или вам может потребоваться отключить функцию, которая автоматически преобразует вкладки в пробелы.
используйте $ (), чтобы назначить выход
cat
в переменную так:VAR=$(cat <<'END_HEREDOC' abc'asdf" $(dont-execute-this) foo"bar"'' END_HEREDOC ) # this will echo variable with new lines intact echo "$VAR" # this will echo variable without new lines (changed to space character) echo $VAR
убедившись в том, чтобы размежевать, начиная END_HEREDOC с одинарными.
обратите внимание, что окончание heredoc разделитель
END_HEREDOC
должен быть один на линии (следовательно, конечная скобка находится на следующей строке).спасибо
@ephemient
для ответа.
Это вариация метода Денниса, выглядит более элегантно в скриптах.
функции определение:
define(){ IFS='\n' read -r -d '' || true; }
использование:
define VAR <<'EOF' abc'asdf" $(dont-execute-this) foo"bar"'' EOF echo "$VAR"
наслаждайтесь
p. s. made a 'read loop' версия для оболочек, которые не поддерживают
read -d
. должен работать сset -eu
и непарные обратные кавычки, но не очень хорошо проверено:define(){ o=; while IFS="\n" read -r a; do o="$o$a"' '; done; eval "=$o"; }
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
добавление комментария здесь в качестве ответа, так как у меня нет достаточно точек повторения, чтобы прокомментировать ваш текст вопроса.
по-прежнему нет решения, которое сохраняет новые строки.
это не так - вы, вероятно, просто вводится в заблуждение поведением echo:
echo $VAR # strips newlines
echo "$VAR" # preserves newlines
массив является переменной, поэтому в этом случае mapfile будет работать
mapfile y <<z abc'asdf" $(dont-execute-this) foo"bar"'' z
тогда вы можете печатать так
printf %s "${y[@]}"
ответвляется Нил, вам часто не нужен 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"''
присвоить значение 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 )"
я обнаружил, что мне нужно прочитать строку с нулем в ней, так что вот решение, которое будет читать что-нибудь вы бросаете на нее. Хотя, если вы действительно имеете дело с 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
спасибо ответ dimo414, это показывает, как его большое решение работает, и показывает, что вы можете иметь кавычки и переменные в тексте легко, а также:
пример вывода
$ ./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 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