| Advanced Bash-Scripting Guide: A complete guide to shell scripting, using Bash | ||
|---|---|---|
| Prev | Chapter 3. Tutorial / Reference | Next |
3.15. Here Documents
A here document uses a special form of I/O redirection to feed a command script to an interactive program, such as ftp, telnet, or ex. Typically, the script consists of a command list to the program, delineated by a limit string. The special symbol << precedes the limit string. This has the effect of redirecting the output of a file into the program, similar to interactive-program < command-file, where command-file contains
1 command #1 2 command #2 3 ... |
The "here document" alternative looks like this:
1 #!/bin/bash 2 interactive-program <<LimitString 3 command #1 4 command #2 5 ... 6 LimitString |
Choose a limit string sufficiently unusual that it will not occur anywhere in the command list and confuse matters.
Note that here documents may sometimes be used to good effect with non-interactive utilities and commands.
Example 3-125. dummyfile: Creates a 2-line dummy file
1 #!/bin/bash 2 3 # Non-interactive use of 'vi' to edit a file. 4 # Emulates 'sed'. 5 6 E_BADARGS=65 7 8 if [ -z "$1" ] 9 then 10 echo "Usage: `basename $0` filename" 11 exit $E_BADARGS 12 fi 13 14 TARGETFILE=$1 15 16 vi $TARGETFILE <<x23LimitStringx23 17 i 18 This is line 1 of the example file. 19 This is line 2 of the example file. 20 ^[ 21 ZZ 22 x23LimitStringx23 23 24 # Note that ^[ above is a literal escape 25 # typed by Control-V Escape. 26 27 exit 0 |
The above script could just as effectively have been implemented with ex, rather than vi. Here documents containing a list of ex commands are common enough to form their own category, known as ex scripts.
Example 3-126. broadcast: Sends message to everyone logged in
1 #!/bin/bash 2 3 wall <<zzz23EndOfMessagezzz23 4 Dees ees a message frrom Central Headquarters: 5 Do not keel moose! 6 # Other message text goes here. 7 # Note: Comment lines printed by 'wall'. 8 zzz23EndOfMessagezzz23 9 10 # Could have been done more efficiently by 11 # wall <message-file 12 13 exit 0 |
Example 3-127. Multi-line message using cat
1 #!/bin/bash 2 3 # 'echo' is fine for printing single line messages, 4 # but somewhat problematic for for message blocks. 5 # A 'cat' here document overcomes this limitation. 6 7 cat <<End-of-message 8 ------------------------------------- 9 This is line 1 of the message. 10 This is line 2 of the message. 11 This is line 3 of the message. 12 This is line 4 of the message. 13 This is the last line of the message. 14 ------------------------------------- 15 End-of-message 16 17 exit 0 18 19 20 #-------------------------------------------- 21 # Code below disabled, due to "exit 0" above. 22 23 # S.C. points out that the following also works. 24 echo "------------------------------------- 25 This is line 1 of the message. 26 This is line 2 of the message. 27 This is line 3 of the message. 28 This is line 4 of the message. 29 This is the last line of the message. 30 -------------------------------------" 31 # However, text may not include double quotes unless they are escaped. |
The - option to mark a here document limit string (<<-LimitString) suppresses tabs (but not spaces) in the output. This may be useful in making a script more readable.
Example 3-128. Multi-line message, with tabs suppressed
1 #!/bin/bash 2 # Same as previous example, but... 3 4 # The - option to a here document <<- 5 # suppresses tabs in the body of the document, 6 # but *not* spaces. 7 8 cat <<-ENDOFMESSAGE 9 This is line 1 of the message. 10 This is line 2 of the message. 11 This is line 3 of the message. 12 This is line 4 of the message. 13 This is the last line of the message. 14 ENDOFMESSAGE 15 # The output of the script will be flush left. 16 # Leading tab in each line will not show. 17 18 # Above 5 lines of "message" prefaced by a tab, not spaces. 19 # Spaces not affected by <<- . 20 21 22 exit 0 |
A here document supports parameter and command substitution. It is therefore possible to pass different parameters to the body of the here document, changing its output accordingly.
Example 3-129. Here document with parameter substitution
1 #!/bin/bash 2 # Another 'cat' here document, using parameter substitution. 3 4 # Try it with no command line parameters, ./scriptname 5 # Try it with one command line parameter, ./scriptname Mortimer 6 # Try it with one two-word quoted command line parameter, ./scriptname "Mortimer Jones" 7 8 CMDLINEPARAM=1 # Expect at least command line parameter. 9 10 if [ $# -ge $CMDLINEPARAM ] 11 then 12 NAME=$1 # If more than one command line param, then just take the first. 13 else 14 NAME="John Doe" # Default, if no command line parameter. 15 fi 16 17 RESPONDENT="the author of this fine script" 18 19 20 cat <<Endofmessage 21 22 Hello, there, $NAME. 23 Greetings to you, $NAME, from $RESPONDENT. 24 25 # This comment shows up in the output (why?). 26 27 Endofmessage 28 29 # Note that the blank lines show up in the output. 30 # So does the "comment". 31 32 exit 0 |
Quoting or escaping the "limit string" at the head of a here document disables parameter substitution within its body. This has very limited usefulness.
Example 3-130. Parameter substitution turned off
1 #!/bin/bash 2 # A 'cat' here document, but with parameter substitution disabled. 3 4 NAME="John Doe" 5 RESPONDENT="the author of this fine script" 6 7 cat <<'Endofmessage' 8 9 Hello, there, $NAME. 10 Greetings to you, $NAME, from $RESPONDENT. 11 12 Endofmessage 13 14 # No parameter substitution when the "limit string" is quoted or escaped. 15 # Either of the following at the head of the here document would have the same effect. 16 # cat <<"Endofmessage" 17 # cat <<\Endofmessage 18 19 exit 0 |
This is a useful script containing a here document with parameter substitution.
Example 3-131. upload: Uploads a file pair to "Sunsite" incoming directory
1 #!/bin/bash 2 3 # upload 4 # upload file pair (filename.lsm, filename.tar.gz) 5 # to incoming directory at Sunsite 6 7 8 if [ -z "$1" ] 9 then 10 echo "Usage: `basename $0` filename" 11 exit 65 12 fi 13 14 15 Filename=`basename $1` 16 # Strips pathname out of file name 17 18 Server="metalab.unc.edu" 19 Directory="/incoming/Linux" 20 # These need not be hard-coded into script, 21 # may instead be changed to command line argument. 22 23 Password="your.e-mail.address" 24 # Change above to suit. 25 26 ftp -n $Server <<End-Of-Session 27 # -n option disables auto-logon 28 29 user anonymous "$Password" 30 binary 31 bell 32 # Ring 'bell' after each file transfer 33 cd $Directory 34 put "$Filename.lsm" 35 put "$Filename.tar.gz" 36 bye 37 End-Of-Session 38 39 exit 0 |
It is possible to use : as a dummy command accepting output from a here document. This, in effect, creates an "anonymous" here document.
Example 3-132. "Anonymous" Here Document
1 #!/bin/bash
2
3 : <<TESTVARIABLES
4 ${HOSTNAME?}${USER?}${MAIL?} # Print error message if one of the variables not set.
5 TESTVARIABLES
6
7 exit 0 |
![]() | Here documents create temporary files, but these files are deleted after opening and are not accessible to any other process.
|
![]() | Some utilities will not work in a here document. |
For those tasks too complex for a "here document", consider using the expect scripting language, which is specifically tailored for feeding input into interactive programs.


