Understanding Here Document in Linux: Examples

Following the previous article on understanding Here Document and Here String in Linux, this article presents some examples for reference.

1. cat and heredoc

<span>cat</span> using <span>heredoc</span> in its simplest form looks like this:

cat << EOF
123
456
hello, world
EOF

Used with a pipe:

# cat_heredoc.sh

cat << EOF | grep 123
123
456
hello, world
EOF

<span>Output:</span>

bash-5.3$ bash cat_here_doc.sh
123

In the shell, <span>interactive input</span> is also possible:

bash-5.3$ cat << EOF | grep 123
> 123
> 456
> hello, world
> EOF
123

Can we input from both <span>heredoc</span> and a file at the same time? Let’s try it.

# Create a new file word.txt
echo "this is word.txt" > word.txt

Try the following script:

# cat_heredoc.sh

cat << EOF word.txt
123
456
hello, world
EOF

echo "#------------#"

cat word.txt << EOF
123
456
hello, world
EOF

The running result shows that heredoc failed, as follows:

bash-5.3$ bash cat_here_doc.sh
this is word.txt
#------------#
this is word.txt

There was no error message, but the content of heredoc was not output.

The author eventually tested it out, please continue reading.

# cat_heredoc.sh

cat - << EOF word.txt
123
456
hello, world
EOF

echo "#------------#"

cat word.txt - << EOF
123
456
hello, world
EOF

This time it succeeded, both heredoc and file content were output.

bash-5.3$ bash cat_here_doc.sh
123
456
hello, world
this is word.txt
#------------#
this is word.txt
123
456
hello, world

The key point here is that <span>-</span> is used as standard input. If that’s the case, can we use the number <span>0</span>? The author’s test result is: no! It seems that here <span>0</span> is just a regular number, with no other special meaning.

<span>-</span> as standard input is a convention in <span>Unix/Linux</span> systems, but not all commands support it. Commands like <span>cat</span>, <span>grep</span>, <span>sed</span>, <span>awk</span> support it, while the <span>-</span> in the <span>cd</span> command has a special meaning, so the usage scenario should depend on the actual situation of the command.

Another way of writing is also feasible.

# cat_heredoc.sh

cat /dev/stdin << EOF word.txt
123
456
hello, world
EOF

Changing <span>-</span> to <span>/dev/stdin</span>

bash-5.3$ bash cat_here_doc.sh
123
456
hello, world
this is word.txt

As shown, the effect is the same.

/dev/stdin[1] is the <span>duplicated</span> of standard input. The author speculates that as long as the command itself supports reading from <span>standard input</span>, it can use <span>/dev/stdin</span> to read <span>heredoc</span>, but it turns out this idea is <span>not quite right</span>.

# cat_heredoc.sh

# Parameter position is wrong.
grep /dev/stdin << EOF 123
123
456
EOF

echo "#------------#"

# ok
grep 123 /dev/stdin << EOF
123
456
EOF

<span>Running result:</span>

bash-5.3$ bash cat_here_doc.sh
grep: 123: No such file or directory
#------------#
123

<span>grep /dev/stdin << EOF 123</span> treats <span>123</span> as a filename.

At this point, it is clear that whether it is <span>cat</span> or <span>grep</span>, they can use <span>/dev/stdin</span> because their parameters indeed require specifying a file. When specifying <span>/dev/stdin</span>, it is equivalent to specifying a file, but this file is special as it is <span>standard input</span>, and then using <span>heredoc</span> for redirection input achieves the desired effect. The reason why <span>cat</span> can use <span>/dev/stdin</span> is the same.

Here, the author suddenly realizes the design philosophy of <span>everything is a file</span>.

2. python and heredoc

Here, <span>python</span> can be replaced with other scripting languages.

<span>Template code</span>

output=$(python << EOF
import sys
print(sys.path)
EOF
)
echo $output

<span>Calculating the area of a circle</span>

# bash_py.sh

radius=2.5

area=$(python << EOF
import math
radius=${radius}
print(math.pi * radius * radius)
EOF
)
echo $area
# Area of the circle
bash-5.3$ bash bash_py.sh
19.634954084936208

3. ftp and heredoc

<span>ftp</span> and other interactive commands collaborating with heredoc are also worth learning about.

#!/bin/bash

BACKUP_FILE="backup_$(date +%Y%m%d).tar.gz"
FTP_SERVER="ftp.server.com"
FTP_USER="username"
FTP_PASS="password"

# Create backup
tar -czf $BACKUP_FILE /important/data

# Upload to FTP
ftp -n << EOF
open $FTP_SERVER
user $FTP_USER$FTP_PASS
binary
put ${BACKUP_FILE}
quit
EOF

echo "Backup ${BACKUP_FILE} has been uploaded"

4. Functions and heredoc

# func_heredoc.sh

function GetPersonalData()
{
    read name
    read age
    read address
}

GetPersonalData << EOF
张三
20
中国
EOF


echo "$name"
echo "$address"

<span>Running result:</span>

bash-5.3$ bash func_heredoc.sh
张三
中国

5. Anonymous heredoc

<span>The syntax is as follows:</span>

: << EOF
These contents will not be displayed
Suitable for comments or documentation
EOF

Below is an example of a commented code block.

#!/usr/bin/env bash
# test.sh

: << 'EOF'
radius=2.5
result=$(awk -v r=$radius'BEGIN {printf "%.3f", 3.14159 * r * r}')
echo "area: $result"
EOF


: << EOF
The previous code for calculating the area of a circle has been commented out and will not execute
EOF

echo 'hello, world!'

<span>Running result:</span>

bash-5.3$ bash test.sh
hello, world!

If it is an unquoted <span>heredoc</span>, variable expansion and other operations will be executed, just not output.

# test.sh

name="张三"
arg=20

: << EOF
${name}的地址是:${address?}
EOF

echo $?

<span>Running result:</span>

bash-5.3$ bash test.sh
test.sh: 行 6: address: 参数未设置

References

[1]

/dev/stdin: https://www.gnu.org/software/bash/manual/html_node/Redirections.html

Leave a Comment