How does cat EOF work in bash?
This is called heredoc format to provide a string into stdin. See https://en.wikipedia.org/wiki/Here_document#Unix_shells for more details.
From man bash
:
Here Documents
This type of redirection instructs the shell to read input from
the current source until a line
containing only word (with no trailing
blanks) is seen.All of the lines read up to that point are then used as the
standard input for a command.The format of here-documents is:
<<[-]word
here-document
delimiter
No 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. In the latter case, the
character sequence\<newline>
is
ignored, and\
must be used to quote the characters\
,$
, and`
.If the redirection operator is
<<-
, then all leading tab characters
are stripped from input lines and the
line containing delimiter. This
allows here-documents within shell scripts to be indented in a natural fashion.
What is EOF!! in the bash script?
On the command line, !!
would be expanded to the last command executed. Bash will print the line for you:
$ ls
a.txt b.txt
$ cat <<EOF!!
cat <<EOFls
>
In a script, though, history expansion is disabled by default, so the exclamation marks are part of the word.
#! /bin/bash
ls
cat <<EOF!!
echo 1
EOFls
echo 2
Produces:
a.txt b.txt
script.sh: line 7: warning: here-document at line 3 delimited by end-of-file (wanted `EOF!!')
echo 1
EOFls
echo 2
To enable history and history expansion in a script, add the following lines:
set -o history
set -H
What does @(cat - EOF do in Bash?
<(...)
is a process substitution. Bash creates a fifo in some directory and run the command inside <(...)
and substitutes the expression with the fifo name. Process substitutions have (strange) lifetime rules, but they are usually valid till the end of command or line. For example:
$ cmd=<(echo 123); echo cmd=$cmd; cat $cmd
cmd=/dev/fd/63
123
<<-EOF
is a here document. If there is -
in front of the delimeter then leading tabs on following lines including the line with delimeter are ignored. (Note: stackoverflow doesn't preserve tabs).
$ echo -e '
cat <<EOF
\tblabla
EOF
cat <<-EOF
\t\t\t\t\tblabla
\t\t\t\t\t\t\t\t\t\t\t\t\tEOF
' > file.sh
$ bash ./file.sh
blabla
blabla
notify @<(...)
just substitutes the <(...)
part inside for some /dev/fd/<number>
and executes notify @/dev/fd/<number>
. Probably the @
is used for notify
process to indicate it should read from file and the rest of the argument is the filename. Then the cat
process that has tied output to /dev/fd/<number>
fifo created with process substitution, the cat
process receives the here document content { <more json data> }
on standard input. cat
outputs standard input to output and then I guess notify
reads the fifo and receives the characters.
Bash - difference between EOF and 'EOF'
/bin/bash<<EOF
#!/bin/bash
echo $BASH_VERSION
EOF
As you can infer from the error message, the heredoc is being expanded to:
/bin/bash<<EOF
#!/bin/bash
echo 5.0.17(1)-release
EOF
It sounds like that's what you expect: it's being expanded to the outer shell's version. The problem isn't with the heredoc or the expansion; it's that unquoted parentheses are a syntax error. Try running just the echo
command by hand and you'll get the same error:
$ echo 5.0.17(1)-release
bash: syntax error near unexpected token `('
To fix this, you could add extra quotes:
/bin/bash<<EOF
echo '$BASH_VERSION'
EOF
This will work and print the outer shell's version. I used single quotes to demonstrate that these quotes will not inhibit variable expansion. The outer shell doesn't see these quotes. Only the inner shell does.
(I also got rid of the #!/bin/bash
shebang line. There's no need for it since you're explicitly invoking bash.)
However, quoting is not 100% robust. If $BASH_VERSION
happened to contain single quotes you'd have a problem. The quotes make parentheses (
)
safe but they aren't foolproof. As a general technique, if you want this to be completely safe no matter what special characters are in play you'll have to jump through some ugly hoops.
Use
printf '%q'
to escape all special characters./bin/bash <<EOF
echo $(printf '%q' "$BASH_VERSION")
EOFThis will expand to
echo 5.0.17\(1\)-release
.Pass it in as an environment variable and use
<<'EOF'
to disable interpolation inside the script.OUTER_VERSION="$BASH_VERSION" /bin/bash <<'EOF'
echo "$OUTER_VERSION"
EOFThis would be my choice. I prefer use the
<<'EOF'
form whenever possible. Having the parent shell interpolate the script being passed to a child shell can be confusing and difficult to reason about. Also, the explicit$OUTER_VERSION
variable makes it crystal clear what's happening.Use
bash -c 'script'
instead of a heredoc and then pass the version in as a command-line argument.bash -c 'echo "$1"' bash "$BASH_VERSION"
I might go with this for a single-line script.
bash - nested EOF
Just use a different delimiter on the outer cat, "EOF" isn't special in any way to the shell:
cat - << REALEND > file1.sh
echo first
cat - << EOF > file2.sh
echo second
EOF
echo again first
REALEND
Results in this content in file1.sh
echo first
cat - << EOF > file2.sh
echo second
EOF
echo again first
Shell script 'read' doesnt work with 'EOF'
Just close the HEREDOC, like this:
while read -r name port ignored; do
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: $name
namespace: nussa
spec:
hosts:
- $name.nussa.svc.cluster.local
http:
- route:
- destination:
host: $name
port:
number: $port
subset: v1
EOF
done <svc1.data
EOF issue in shell script
The <<EOF
indicates the start of heredoc
A here document is a special-purpose code block. It uses a form of I/O redirection to feed a command list to an interactive program or a command, such as ftp, cat, or the ex text editor.
You should then close your heredoc code block, like that:
func_some()
{
cd some_directory
lftp -u user,'password' sftp://192.168.xx.xx <<EOF
cd some_directory
mget ADMS_report_*${2}${3}${4}*.txt
EOF
}
as otherwise it will keep on searching for the limit string (EOF
),
and fail with a syntax error, when the end of file is reached.
Note that the limit string, must be placed at the start of the line,
with no spaces in front of it.
bash script within EOF unable to pass arguments to function
Quote the << 'EOF'
to prevent the $
in the function from being expanded before the function is defined.
sudo -i -u $USER bash << 'EOF'
func(){
echo $1
}
func 'Test message for channel'
EOF
See the Bash manual on Here Documents. This behaviour applies to all Bourne shell derivatives — Bash, POSIX shells, ksh
, etc.
I am getting this EOF error when running this bash script
You are missing a closing "
on the line where you're outputting:
echo "Creating Output Directory as: $_file
Related Topics
Graphing The Dag Generated by Make
Read Serial Data Without High CPU Use
Why Kernel Needs Virtual Addressing
Why Doesn't Tar Preserve File Permissions
Securing Udp - Openssl or Gnutls or ...
Why Use G++ Instead of Gcc to Compile *.Cc Files
Self Updating Bash Script from Github
How to Open Serial Port in Linux Without Changing Any Pin
How to Copy The Top 10 Most Recent Files from One Directory to Another
"Must Be Connected to a Terminal Error" with Screen -X Command on a Linux Container
In Linux, How to Create a File Descriptor for a Memory Region
How to Detect If a Server Is Using Spdy
Kafka Console Consumer with Kerberos Authentication
Does I2C Driver Need to Be Implemented Just Like Any Other Character Device Driver