| |

LFCS 29 ๐Ÿง Here Documents and Here Strings

A command reads from the standard input, and the input usually comes from the file or the pipe. But sometimes the input is the short, the inline, and the not worth the file. The cat << EOF feeds the block of the text to the cat without the temporary file. The grep 'pattern' <<< "$variable" feeds the string to the grep without the echo. The here document and the here string are the redirection operators that embed the input directly in the command. They are the shell features, and they are the standard for the configuration generation, the SQL scripts, the SSH commands, and the multiline strings. The LFCS exam tests them as part of the “Use streams, pipes, and redirects” objective.

The here document is the << operator. The syntax is command << DELIMITER followed by the lines of the input, and the DELIMITER line ends the input. The delimiter is the arbitrary word, and the EOF is the convention. The quoted delimiter (<< 'EOF') prevents the variable expansion, and the unquoted (<< EOF) allows it. The <<- strips the leading tabs, and the <<< is the here string for the single line.

The here string is the <<< operator. The syntax is command <<< "string", and the string is the input. The shell appends the newline, and the command reads it as the single line. The here string is the shorthand for the echo "string" | command, and it is the cleaner and the faster.

This chapter covers three areas. First, why the here documents and the here strings exist โ€” the inline-input problem and the temporary-file avoidance. Second, the syntax โ€” the <<, the <<-, the <<<, the quoted vs the unquoted delimiter, and the variable expansion. Third, the common patterns โ€” the SQL scripts, the SSH commands, the configuration generation, the multiline strings, and the pitfalls. The chapter ends with a complete example session, a quick reference, best practices, common pitfalls, real-world examples, and diagrams showing the here document flow.

Key point: The here document is the << operator that feeds the multiline input to the command, and the here string is the <<< operator that feeds the single line. The quoted delimiter (<< 'EOF') prevents the variable expansion, and the unquoted (<< EOF) allows it. The <<- strips the leading tabs. The here document and the here string are the inline input without the temporary file.


Why here documents and here strings exist

The inline-input problem. The command reads the standard input, and the input is the short. The cat file.txt | command needs the file, and the echo 'input' | command needs the pipe. The here document and the here string embed the input directly in the command, and the temporary file and the echo pipe are the unnecessary. The command <<< 'input' is the shorthand for the echo 'input' | command, and the command << EOF is the multiline.

The temporary-file problem. The SQL script, the configuration, and the SSH command need the multiline input. The temporary file is the way, but the file must be created, the written, the read, and the deleted. The here document skips the file: the input is the inline, and the command reads it. The mysql << EOF is the SQL without the schema.sql.

The variable-expansion problem. The here document with the unquoted delimiter allows the variable expansion, and the quoted delimiter prevents it. The cat << EOF expands the $variable, and the cat << 'EOF' does not. The choice is the important for the scripts that generate the configuration with the variables and the scripts that contain the literal $.

The indentation problem. The here document must have the delimiter at the start of the line, unless the <<- is used. The <<- strips the leading tabs, and it allows the indentation in the script. The spaces are not the stripped, only the tabs.

The single-line problem. The here string is the single-line input. The grep 'pattern' <<< "$var" is the cleaner than the echo "$var" | grep 'pattern'. The here string appends the newline, and the command reads it.

The trade-off. The here document is the multiline and the readable, and the here string is the single-line and the concise. The temporary file is the reusable and the debuggable, and the here document is the inline. The trade-off is between the file and the inline, and the choice depends on the reuse.


a. The here document syntax

The here document is the << operator. The syntax is the command << DELIMITER, the lines, and the DELIMITER.

cat << EOF
line 1
line 2
line 3
EOF

The cat reads the three lines, and the EOF ends the input. The delimiter is the arbitrary, and the EOF is the convention.

The variable expansion. The unquoted delimiter expands the variables:

NAME="Alice"
cat << EOF
Hello, $NAME
EOF
# the Hello, Alice

The $NAME is the expanded, and the $(command) is the executed.

The quoted delimiter. The quoted delimiter prevents the expansion:

NAME="Alice"
cat << 'EOF'
Hello, $NAME
EOF
# the Hello, $NAME

The $NAME is the literal, and the $(command) is the literal. The quoted delimiter is the way to pass the literal $.

The <<-. The <<- strips the leading tabs:

if true; then
	cat <<- EOF
	line 1
	line 2
	EOF
fi

The leading tabs are the stripped, and the delimiter can be the indented. The spaces are not the stripped, and the tabs are the requirement.

The multiple here documents. The command can have the multiple:

cat << EOF1 << EOF2
the first
EOF1
the second
EOF2
# the cat reads the second only

The cat reads the last one, and the first is the ignored. The multiple is the rare.

The here document in the pipeline. The here document is the stdin, and the pipeline is the stdout:

cat << EOF | grep 'line'
line 1
line 2
EOF

The cat feeds the grep, and the here document is the source.

The here document to the file. The here document with the >:

cat << EOF > config.txt
key=value
EOF

The cat writes the file, and the here document is the content. The cat is the unnecessary, and the > can be used directly:

cat > config.txt << EOF
key=value
EOF

The cat > file << EOF is the pattern, and the cat is the writer.


b. The here string syntax

The here string is the <<< operator. The syntax is the command <<< "string".

grep 'pattern' <<< "the string to search"
wc -w <<< "the one two three"
cat <<< "the single line"

The grep reads the string, and the wc counts the words. The here string is the shorthand for the echo "string" | command.

The variable. The here string with the variable:

NAME="Alice"
grep 'Alice' <<< "$NAME"

The $NAME is the expanded, and the grep reads the Alice.

The command substitution. The here string with the $():

wc -l <<< "$(ls)"

The $(ls) is the executed, and the wc counts the lines.

The arithmetic. The here string with the $(( )):

echo $(( $(cat <<< "5") + 3 ))
# the 8

The here string is the input, and the arithmetic is the output.

The newline. The here string appends the newline:

wc -c <<< "abc"
# the 4 (the a, the b, the c, and the newline)

The here string adds the newline, and the wc -c counts it.

The read with the here string. The read reads the here string:

read -r var <<< "the value"
echo "$var"
# the value

The read reads the var from the here string.

The multiple words. The here string with the multiple words:

read -r first second <<< "the one two three"
echo "$first"  # the the
echo "$second" # the one two three

The read splits the words, and the last variable gets the rest.


c. The common patterns

The SQL script. The here document to the mysql:

mysql -u root -p << EOF
SELECT * FROM users;
SELECT * FROM orders;
EOF

The SQL is the inline, and the temporary file is the avoided.

The SSH command. The here document to the ssh:

ssh user@host << EOF
cd /app
git pull
npm install
npm run build
EOF

The commands are the inline, and the ssh runs them.

The configuration generation. The here document with the variables:

cat > /etc/app/config.conf << EOF
[server]
host = $HOST
port = $PORT
[debug]
enabled = $DEBUG
EOF

The variables are the expanded, and the config is the generated.

The literal configuration. The here document with the quoted delimiter:

cat > script.sh << 'EOF'
#!/bin/bash
echo "$HOME"
echo "$(date)"
EOF

The $HOME and the $(date) are the literal, and the script is the generated.

The multiline string. The here string with the $'...':

cat <<< $'line 1\nline 2'

The $'...' interprets the escape, and the \n is the newline.

The JSON generation. The here document with the JSON:

cat > data.json << EOF
{
  "name": "$NAME",
  "age": $AGE
}
EOF

The variables are the expanded, and the JSON is the generated. The jq is the validation.

The YAML generation. The here document with the YAML:

cat > docker-compose.yml << EOF
services:
  app:
    image: $IMAGE
    ports:
      - "$PORT:3000"
EOF

The YAML is the generated, and the variables are the expanded.

The script generation. The here document with the sudo:

sudo tee /etc/systemd/system/app.service << EOF
[Unit]
Description=The App
[Service]
ExecStart=/usr/bin/app
[Install]
WantedBy=multi-user.target
EOF

The sudo tee writes the root-owned file, and the here document is the content.

The nested here document. The here document in the here document:

cat << OUTER
The outer
$(cat << INNER
The inner
INNER
)
The outer again
OUTER

The $() runs the inner, and the outer has the result.

The here document with the while read. The here document with the loop:

while IFS= read -r line; do
  echo "Line: $line"
done << EOF
line 1
line 2
EOF

The while read reads the each line, and the here document is the source.

The here string with the jq. The here string with the JSON:

jq '.name' <<< '{"name": "Alice"}'
# the "Alice"

The jq reads the JSON from the here string.

The here document with the openssl. The here document with the openssl:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes << EOF
US
California
San Francisco
The Company
The Department
the.example.com
admin@example.com
EOF

The openssl prompts are the answered, and the certificate is the generated.


Complete Example Session

# ============================================
# PART 1: THE BASIC HERE DOCUMENT
# ============================================

cat << EOF
line 1
line 2
line 3
EOF


# ============================================
# PART 2: THE VARIABLE EXPANSION
# ============================================

NAME="Alice"
cat << EOF
Hello, $NAME
EOF
# the Hello, Alice


# ============================================
# PART 3: THE QUOTED DELIMITER
# ============================================

NAME="Alice"
cat << 'EOF'
Hello, $NAME
EOF
# the Hello, $NAME


# ============================================
# PART 4: THE TABS STRIPPED
# ============================================

if true; then
	cat <<- EOF
	line 1
	line 2
	EOF
fi


# ============================================
# PART 5: THE HERE DOCUMENT TO THE FILE
# ============================================

cat > config.txt << EOF
key=value
another=value
EOF


# ============================================
# PART 6: THE SUDO TEE
# ============================================

sudo tee /etc/systemd/system/app.service << EOF
[Unit]
Description=The App
[Service]
ExecStart=/usr/bin/app
[Install]
WantedBy=multi-user.target
EOF


# ============================================
# PART 7: THE HERE STRING
# ============================================

grep 'pattern' <<< "the string to search"
wc -w <<< "the one two three"
read -r var <<< "the value"
echo "$var"


# ============================================
# PART 8: THE HERE STRING WITH THE COMMAND
# ============================================

wc -l <<< "$(ls)"
jq '.name' <<< '{"name": "Alice"}'
echo $(( $(cat <<< "5") + 3 ))


# ============================================
# PART 9: THE SQL SCRIPT
# ============================================

mysql -u root -p << EOF
SELECT * FROM users;
SELECT * FROM orders;
EOF


# ============================================
# PART 10: THE LFCS PIPELINE
# ============================================

# The SSH command
ssh user@host << EOF
cd /app
git pull
npm install
npm run build
EOF

# The config generation
cat > /etc/app/config.conf << EOF
[server]
host = $HOST
port = $PORT
EOF

# The literal script
cat > script.sh << 'SCRIPT'
#!/bin/bash
echo "$HOME"
SCRIPT
chmod +x script.sh

# The while read with the here document
while IFS= read -r line; do
  echo "Line: $line"
done << EOF
line 1
line 2
EOF

# The JSON with the here document
cat > data.json << EOF
{
  "name": "$NAME",
  "age": $AGE
}
EOF

# The here string with the jq
jq '.name' <<< '{"name": "Alice"}'

# The here string with the read
read -r first second <<< "the one two three"
echo "$first"  # the the
echo "$second" # the one two three

# The here document with the pipeline
cat << EOF | grep 'line'
line 1
line 2
line 3
EOF

The ten parts show the basic here document, the variable expansion, the quoted delimiter, the tabs stripped, the here document to the file, the sudo tee, the here string, the here string with the command, the SQL script, and the LFCS pipeline.


Quick Reference

The Operators

The operatorThe purpose
<< DELIMThe here document
<< 'DELIM'The here document, no expansion
<<- DELIMThe here document, the tabs stripped
<<< "string"The here string

The Delimiter

The formThe expansion
<< EOFThe variables and the commands
<< 'EOF'The literal
<< "EOF"The literal (the same as the quoted)
<< \EOFThe literal (the escaped)

The Common Patterns

The patternThe command
The SQLmysql << EOF
The SSHssh host << EOF
The configcat > file << EOF
The privilegedsudo tee file << EOF
The literalcat > file << 'EOF'
The loopwhile read << EOF
The here stringgrep 'x' <<< "$var"

The Here String vs the Echo Pipe

The aspectThe here stringThe echo pipe
The syntaxcmd <<< "$var"echo "$var" | cmd
The newlineThe appendedThe appended
The subshellNoYes
The speedThe fasterThe slower

The Common Commands

The commandThe purpose
cat << EOFThe read the multiline
cat > file << EOFThe write the file
mysql << EOFThe SQL
ssh host << EOFThe remote
sudo tee file << EOFThe privileged
jq <<< '{}'The JSON
read <<< "$var"The parse

Best Practices

โœ… Do This:

# Use the quoted delimiter for the literal
cat << 'EOF'                                                              # โœ…
echo "$HOME"
EOF
# Use the here document for the multiline
mysql << EOF                                                              # โœ…
SELECT * FROM users;
EOF
# Use the here string for the single line
grep 'pattern' <<< "$var"                                                 # โœ…
# Use the sudo tee for the privileged
sudo tee /etc/file << EOF                                                 # โœ…
# Use the <<- for the indentation
cat <<- EOF                                                               # โœ…
	line
	EOF
# Use the read with the here string
read -r var <<< "value"                                                   # โœ…

โŒ Don’t Do This:

# Don't use the unquoted delimiter for the literal
cat << EOF                                                                // โŒ
echo "$HOME"  # the $HOME is the expanded
EOF
# Don't forget the delimiter
cat << EOF                                                                // โŒ
line 1
# the delimiter is the missing
# Don't use the here document for the single line
cat << EOF                                                                // โœ… (the here string is the simpler)
line
EOF
# Don't use the spaces with the <<-
cat <<- EOF                                                               // โŒ
    line  # the spaces are NOT stripped, only the tabs
    EOF
# Don't forget the newline
printf 'abc' <<< ""                                                       // โŒ
# Don't use the > for the sudo
sudo cat > /etc/file << EOF                                               // โŒ (the tee is the correct)
EOF
# Don't nest the unquoted here documents
cat << EOF                                                                // โŒ (the $() is the fix)
$(cat << EOF
EOF
)
EOF

Common Pitfalls

The pitfallThe whyThe fix
The variables expandedThe unquoted delimiterUse the << 'EOF'
The $ interpretedThe unquotedQuote the delimiter
The delimiter not foundThe wrong wordMatch the delimiter
The spaces not strippedThe <<- strips the tabs onlyUse the tabs
The sudo failsThe > redirectUse the sudo tee
The here string no newlineThe <<< appendsThe expected
The nested expansionThe unquotedUse the $()

Real-World Examples

1. The SQL Script

mysql << EOF
SELECT * FROM users;
EOF

2. The SSH Command

ssh host << EOF
cd /app
git pull
EOF

3. The Config Generation

cat > config.conf << EOF
host=$HOST
port=$PORT
EOF

4. The Literal Script

cat > script.sh << 'EOF'
#!/bin/bash
echo "$HOME"
EOF

5. The Privileged Write

sudo tee /etc/file << EOF
content
EOF

6. The Here String

grep 'pattern' <<< "$var"

7. The JSON

jq '.name' <<< '{"name": "Alice"}'

8. The Read

read -r var <<< "value"

9. The Loop

while read -r line; do echo "$line"; done << EOF
a
b
EOF

10. The Complete

cat > /etc/app.conf << 'EOF'
key=$LITERAL
EOF

Visual

The Here Document Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE HERE DOCUMENT FLOW                                      โ”‚
โ”‚                                                              โ”‚
โ”‚  cat << EOF                                                  โ”‚
โ”‚  line 1                                                      โ”‚
โ”‚  line 2                                                      โ”‚
โ”‚  line 3                                                      โ”‚
โ”‚  EOF                                                         โ”‚
โ”‚                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  The shell reads the lines until the EOF.            โ”‚    โ”‚
โ”‚  โ”‚  The lines become the stdin of the cat.              โ”‚    โ”‚
โ”‚  โ”‚  The cat prints them to the stdout.                  โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  The here document is the inline stdin.                      โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Quoted vs the Unquoted

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE QUOTED vs THE UNQUOTED                                  โ”‚
โ”‚                                                              โ”‚
โ”‚  THE UNQUOTED (`<< EOF`):                                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  NAME="Alice"                                        โ”‚    โ”‚
โ”‚  โ”‚  cat << EOF                                          โ”‚    โ”‚
โ”‚  โ”‚  Hello, $NAME                                        โ”‚    โ”‚
โ”‚  โ”‚  EOF                                                 โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The output: the Hello, Alice                        โ”‚    โ”‚
โ”‚  โ”‚  The $NAME is the EXPANDED.                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  THE QUOTED (`<< 'EOF'`):                                    โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  NAME="Alice"                                        โ”‚    โ”‚
โ”‚  โ”‚  cat << 'EOF'                                        โ”‚    โ”‚
โ”‚  โ”‚  Hello, $NAME                                        โ”‚    โ”‚
โ”‚  โ”‚  EOF                                                 โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The output: the Hello, $NAME                        โ”‚    โ”‚
โ”‚  โ”‚  The $NAME is the LITERAL.                           โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Privileged Write

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE PRIVILEGED WRITE                                        โ”‚
โ”‚                                                              โ”‚
โ”‚  โŒ THE `>` REDIRECT:                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  sudo cat > /etc/file << EOF                         โ”‚    โ”‚
โ”‚  โ”‚    โ†’ the shell opens the /etc/file as the USER       โ”‚    โ”‚
โ”‚  โ”‚    โ†’ the permission denied                           โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ”‚  โœ… THE `sudo tee`:                                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  sudo tee /etc/file << EOF                           โ”‚    โ”‚
โ”‚  โ”‚    โ†’ the tee runs as the ROOT                        โ”‚    โ”‚
โ”‚  โ”‚    โ†’ the success                                     โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Here String

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  THE HERE STRING                                             โ”‚
โ”‚                                                              โ”‚
โ”‚  grep 'pattern' <<< "the string to search"                   โ”‚
โ”‚                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  The here string is the shorthand for:               โ”‚    โ”‚
โ”‚  โ”‚    echo "the string to search" | grep 'pattern'      โ”‚    โ”‚
โ”‚  โ”‚                                                       โ”‚    โ”‚
โ”‚  โ”‚  The difference:                                     โ”‚    โ”‚
โ”‚  โ”‚    The here string is the faster (the no subshell).  โ”‚    โ”‚
โ”‚  โ”‚    The here string appends the newline.              โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
The here documentThe << operator
The quoted delimiterThe << 'EOF' (the no expansion)
The unquoted delimiterThe << EOF (the expansion)
The tabs strippedThe <<-
The here stringThe <<< operator
The delimiterThe arbitrary word, the EOF the convention
The expansionThe $variable and the $(command)
The privileged writeThe sudo tee
The here string vs the echoThe no subshell

Key takeaways:

  • The here document is the << operator that feeds the multiline input to the command. The cat << EOF reads the lines until the EOF, and the lines become the standard input. The temporary file is the avoided.
  • The quoted delimiter (<< 'EOF') prevents the variable expansion. The $variable and the $(command) are the literal. The unquoted delimiter (<< EOF) allows the expansion.
  • The <<- strips the leading tabs. The delimiter can be the indented with the tabs, and the spaces are not the stripped. The <<- is the important for the script indentation.
  • The here string is the <<< operator that feeds the single line. The grep 'pattern' <<< "$var" is the shorthand for the echo "$var" | grep 'pattern', and it avoids the subshell.
  • The here document is the SQL, the SSH, and the config generation. The mysql << EOF, the ssh host << EOF, and the cat > config << EOF are the patterns.
  • The sudo tee writes the privileged file. The sudo cat > /etc/file fails, because the redirection runs in the user’s shell. The sudo tee /etc/file << EOF works.
  • The here string appends the newline. The wc -c <<< "abc" returns the 4, because the newline is the added.
  • The result is the inline input. The here document and the here string are the temporary file and the echo pipe the avoided. The result is the clean and the efficient shell scripting, which is the foundation of the configuration and the automation.

Remember: The here document is the << operator that feeds the multiline input, and the here string is the <<< operator that feeds the single line. The quoted delimiter prevents the expansion, and the unquoted allows it. The <<- strips the tabs. The result is the inline input, which is the foundation of the shell scripting.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!