How to assign a heredoc value to a variable in Bash?
You can avoid a useless use of cat
and handle mismatched quotes better with this:
$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
If you don't quote the variable when you echo it, newlines are lost. Quoting it preserves them:
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
If you want to use indentation for readability in the source code, use a dash after the less-thans. The indentation must be done using only tabs (no spaces).
$ read -r -d '' VAR <<-'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
If, instead, you want to preserve the tabs in the contents of the resulting variable, you need to remove tab from IFS
. The terminal marker for the here doc (EOF
) must not be indented.
$ IFS='' read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''
Tabs can be inserted at the command line by pressing Ctrl-V Tab. If you are using an editor, depending on which one, that may also work or you may have to turn off the feature that automatically converts tabs to spaces.
Using variables inside a bash heredoc
In answer to your first question, there's no parameter substitution because you've put the delimiter in quotes - the bash manual says:
The format of here-documents is:
<<[-]word
here-document
delimiterNo parameter expansion, command substitution, arithmetic expansion, or
pathname expansion is performed on word. If any characters in word are
quoted, the delimiter is the result of quote removal on word, and the
lines in the here-document are not expanded. If word is unquoted, all
lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion. [...]
If you change your first example to use <<EOF
instead of << "EOF"
you'll find that it works.
In your second example, the shell invokes sudo
only with the parameter cat
, and the redirection applies to the output of sudo cat
as the original user. It'll work if you try:
sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
Can a bash heredoc put its result directly into a variable?
How to put a here-string into a variable in Bash:
In Bash use read
with the -d
delimiter set to null:
IFS= read -r -d '' cmd <<EOC
...blah blah...
EOC
Make sure you really use IFS=
like shown, in front of read
, otherwise any leading and trailing spaces will be trimmed. Make sure you use -r
otherwise some backslashes would be understood as escape backslashes.
Some would argue that it's simpler to just use a plain assignment as:
cmd='
...blah blah...
'
But sometimes you have lots of quotes to the point that it becomes simpler and nicer to use this.
Subtle note. With this, read
returns a failure return code (1) since the null-byte delimiter is not read before EOF. While this is alright most of the times, it can be a problem if you're using set -e
(but you really shouldn't use set -e
anyway). If you want to be sure, add:
IFS= read -r -d '' cmd <<EOC || true
...blah blah...
EOC
Now, seriously, about your problem.
Below is a serious note that you really should take into account: don't put code into strings! it's broken!. Instead, use a function or (still bad, but not broken) an array. Here's how you would use an array:
mycommand=(
docker run
-p "$MY_IP:$LOCAL_PORT:$LOCAL_PORT"
-p "$MY_IP:$PEER_PORT:$PEER_PORT"
-v "$CERT_DIR":/cert
"$ETCD_IMAGE"
--name "$MACHINE.$DOMAIN"
--peer-cert-file=/cert/server-cert.pem
--peer-key-file=/cert/server-key.pem
--peer-ca-file=/cert/ca.pem
--peer-addr="$MY_IP:$PEER_PORT"
--peers="$OIPPC"
)
(observe the quotes that I took time to type, with love).
Then you can safely run it (by safely I mean it's all right if you're having glob characters or quotes or spaces in your arguments) as:
"${mycommand[@]}"
(observe the healthy quotes, again). If you want to print the command, use this:
printf '%s\n' "${mycommand[*]}"
Unfortunately, the line breaks won't be preserved here. But really, that shouldn't be a problem at all. If really needed, you should pass this command through a formatter of some sort (well, very likely it doesn't exist so you'll have to code it yourself). But put the things in the right order: you want to define a command, to execute it (and, optionally format it, for user display), not the other way round, have a string that's nice to the user's eyes that you then have to parse (dangerously) to transform into code.
How to assign variables with Command results with HEREDOC in shell script
It's not at all clear to me what exactly what you are doing, but you should realize that the line a=$(cat $file)
(I've used $() notation rather than backticks to avoid a clash with SO markup and because backticks are a scourge on humanity that should be avoided at all costs) is expanding both $file and the process substitution on the local host. Similarly, the ls -l
is listing the directory on the local host from which you run Jump.Sh. You can avoid that by simply quoting the EOF
:
Jump.Sh ... > sample.csv << 'EOF'
will prevent any expansion locally and pass the raw text as input to Jump.Sh
How do I set a variable to the output of a command in Bash?
In addition to backticks `command`
, command substitution can be done with $(command)
or "$(command)"
, which I find easier to read, and allows for nesting.
OUTPUT=$(ls -1)
echo "${OUTPUT}"
MULTILINE=$(ls \
-1)
echo "${MULTILINE}"
Quoting ("
) does matter to preserve multi-line variable values; it is optional on the right-hand side of an assignment, as word splitting is not performed, so OUTPUT=$(ls -1)
would work fine.
How to pipe a here-document through a command and capture the result into a variable?
This seems to work (based on Ignacio's answer). By using a subshell the here-document is correctly piped into xsltproc while still being passed through tail after.
VERSION=$((xsltproc - ../pom.xml | tail -1) << EOF
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/"><xsl:value-of select="/project/version"/></xsl:template>
</xsl:stylesheet>
EOF
)
How to assign the output of a Bash command to a variable?
Try:
pwd=`pwd`
or
pwd=$(pwd)
Notice no spaces after the equals sign.
Also as Mr. Weiss points out; you don't assign to $pwd
, you assign to pwd
.
Related Topics
Iterating Over File (And Directory) Names with Bash
Sort Command in Not Working Properly in Unix for Sorting a CSV File
How to Check If "S" Permission Bit Is Set on Linux Shell? or Perl
Linker Error When Calling Printf from _Start
How to Stop Apache from Listing the Contents of My User Directories
Permission Denied (Publickey), on Linux Aws Server How to Fix It
How to Split Flv File by Size Using Ffmpeg or Mencoder or Smth Else
Average of Multiple Files Without Considering Missing Values
Will Process Lost Wake-Up Chance in a Preemptive Kernel
Ssh Connection to Ubuntu Open Ssh-Server Requires Login on (Physical) Server via Password First
Bash Assign Output to Variable Inside Here Document
Docker-Compose Stop Working After Docker Desktop Installation on Debian 11
Wc -M in Unix Adds One Character
Libreoffice Command Line Conversion - No Output File
R Programming - Submitting Jobs on a Multiple Node Linux Cluster Using Pbs