📄 here-docs.html
字号:
><P><B>Example 17-8. A script that generates another script</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # generate-script.sh 3 # Based on an idea by Albert Reiner. 4 5 OUTFILE=generated.sh # Name of the file to generate. 6 7 8 # ----------------------------------------------------------- 9 # 'Here document containing the body of the generated script. 10 ( 11 cat <<'EOF' 12 #!/bin/bash 13 14 echo "This is a generated shell script." 15 # Note that since we are inside a subshell, 16 #+ we can't access variables in the "outside" script. 17 18 echo "Generated file will be named: $OUTFILE" 19 # Above line will not work as normally expected 20 #+ because parameter expansion has been disabled. 21 # Instead, the result is literal output. 22 23 a=7 24 b=3 25 26 let "c = $a * $b" 27 echo "c = $c" 28 29 exit 0 30 EOF 31 ) > $OUTFILE 32 # ----------------------------------------------------------- 33 34 # Quoting the 'limit string' prevents variable expansion 35 #+ within the body of the above 'here document.' 36 # This permits outputting literal strings in the output file. 37 38 if [ -f "$OUTFILE" ] 39 then 40 chmod 755 $OUTFILE 41 # Make the generated file executable. 42 else 43 echo "Problem in creating file: \"$OUTFILE\"" 44 fi 45 46 # This method can also be used for generating 47 #+ C programs, Perl programs, Python programs, Makefiles, 48 #+ and the like. 49 50 exit 0</PRE></TD></TR></TABLE><HR></DIV><P> It is possible to set a variable from the output of a here document. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 variable=$(cat <<SETVAR 2 This variable 3 runs over multiple lines. 4 SETVAR) 5 6 echo "$variable"</PRE></TD></TR></TABLE> </P><P>A here document can supply input to a function in the same script.</P><DIVCLASS="EXAMPLE"><HR><ANAME="HF"></A><P><B>Example 17-9. Here documents and functions</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # here-function.sh 3 4 GetPersonalData () 5 { 6 read firstname 7 read lastname 8 read address 9 read city 10 read state 11 read zipcode 12 } # This certainly looks like an interactive function, but... 13 14 15 # Supply input to the above function. 16 GetPersonalData <<RECORD001 17 Bozo 18 Bozeman 19 2726 Nondescript Dr. 20 Baltimore 21 MD 22 21226 23 RECORD001 24 25 26 echo 27 echo "$firstname $lastname" 28 echo "$address" 29 echo "$city, $state $zipcode" 30 echo 31 32 exit 0</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="ANONHEREDOC0"></A></P><P>It is possible to use <SPANCLASS="TOKEN">:</SPAN> as a dummy command accepting output from a here document. This, in effect, creates an <SPANCLASS="QUOTE">"anonymous"</SPAN> here document.</P><DIVCLASS="EXAMPLE"><HR><ANAME="ANONHEREDOC"></A><P><B>Example 17-10. <SPANCLASS="QUOTE">"Anonymous"</SPAN> Here Document</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 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</PRE></TD></TR></TABLE><HR></DIV><P><ANAME="CBLOCK1"></A></P><DIVCLASS="TIP"><TABLECLASS="TIP"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/tip.png"HSPACE="5"ALT="Tip"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>A variation of the above technique permits <SPANCLASS="QUOTE">"commenting out"</SPAN> blocks of code.</P></TD></TR></TABLE></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="COMMENTBLOCK"></A><P><B>Example 17-11. Commenting out a block of code</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # commentblock.sh 3 4 : <<COMMENTBLOCK 5 echo "This line will not echo." 6 This is a comment line missing the "#" prefix. 7 This is another comment line missing the "#" prefix. 8 9 &*@!!++= 10 The above line will cause no error message, 11 because the Bash interpreter will ignore it. 12 COMMENTBLOCK 13 14 echo "Exit value of above \"COMMENTBLOCK\" is $?." # 0 15 # No error shown. 16 17 18 # The above technique also comes in useful for commenting out 19 #+ a block of working code for debugging purposes. 20 # This saves having to put a "#" at the beginning of each line, 21 #+ then having to go back and delete each "#" later. 22 23 : <<DEBUGXXX 24 for file in * 25 do 26 cat "$file" 27 done 28 DEBUGXXX 29 30 exit 0</PRE></TD></TR></TABLE><HR></DIV><DIVCLASS="TIP"><TABLECLASS="TIP"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/tip.png"HSPACE="5"ALT="Tip"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Yet another twist of this nifty trick makes <SPANCLASS="QUOTE">"self-documenting"</SPAN> scripts possible.</P></TD></TR></TABLE></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="SELFDOCUMENT"></A><P><B>Example 17-12. A self-documenting script</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # self-document.sh: self-documenting script 3 # Modification of "colm.sh". 4 5 DOC_REQUEST=70 6 7 if [ "$1" = "-h" -o "$1" = "--help" ] # Request help. 8 then 9 echo; echo "Usage: $0 [directory-name]"; echo 10 sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATIONXX$/p' "$0" | 11 sed -e '/DOCUMENTATIONXX$/d'; exit $DOC_REQUEST; fi 12 13 14 : <<DOCUMENTATIONXX 15 List the statistics of a specified directory in tabular format. 16 --------------------------------------------------------------- 17 The command line parameter gives the directory to be listed. 18 If no directory specified or directory specified cannot be read, 19 then list the current working directory. 20 21 DOCUMENTATIONXX 22 23 if [ -z "$1" -o ! -r "$1" ] 24 then 25 directory=. 26 else 27 directory="$1" 28 fi 29 30 echo "Listing of "$directory":"; echo 31 (printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAME\n" \ 32 ; ls -l "$directory" | sed 1d) | column -t 33 34 exit 0</PRE></TD></TR></TABLE><HR></DIV><P>Using a <AHREF="here-docs.html#CATSCRIPTREF">cat script</A> is an alternate way of accomplishing this.</P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 DOC_REQUEST=70 2 3 if [ "$1" = "-h" -o "$1" = "--help" ] # Request help. 4 then # Use a "cat script" . . . 5 cat <<DOCUMENTATIONXX 6 List the statistics of a specified directory in tabular format. 7 --------------------------------------------------------------- 8 The command line parameter gives the directory to be listed. 9 If no directory specified or directory specified cannot be read, 10 then list the current working directory. 11 12 DOCUMENTATIONXX 13 exit $DOC_REQUEST 14 fi</PRE></TD></TR></TABLE> </P><P>See also <AHREF="contributed-scripts.html#ISSPAMMER2">Example A-27</A> for one more excellent example of a self-documenting script.</P><DIVCLASS="NOTE"><TABLECLASS="NOTE"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/note.png"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Here documents create temporary files, but these files are deleted after opening and are not accessible to any other process.</P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="SCREEN"> <TTCLASS="PROMPT">bash$ </TT><TTCLASS="USERINPUT"><B>bash -c 'lsof -a -p $$ -d0' << EOF</B></TT> <TTCLASS="PROMPT">> </TT><TTCLASS="USERINPUT"><B>EOF</B></TT> <TTCLASS="COMPUTEROUTPUT">lsof 1213 bozo 0r REG 3,5 0 30386 /tmp/t1213-0-sh (deleted)</TT> </PRE></TD></TR></TABLE> </P></TD></TR></TABLE></DIV><DIVCLASS="CAUTION"><TABLECLASS="CAUTION"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/caution.png"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>Some utilities will not work inside a <ICLASS="EMPHASIS">here document</I>.</P></TD></TR></TABLE></DIV><P><ANAME="INDENTEDLS"></A></P><DIVCLASS="WARNING"><TABLECLASS="WARNING"WIDTH="100%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="common/warning.png"HSPACE="5"ALT="Warning"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>The closing <ICLASS="EMPHASIS">limit string</I>, on the final line of a here document, must start in the <ICLASS="EMPHASIS">first</I> character position. There can be <ICLASS="EMPHASIS">no leading whitespace</I>. Trailing whitespace after the limit string likewise causes unexpected behavior. The whitespace prevents the limit string from being recognized.</P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 echo "----------------------------------------------------------------------" 4 5 cat <<LimitString 6 echo "This is line 1 of the message inside the here document." 7 echo "This is line 2 of the message inside the here document." 8 echo "This is the final line of the message inside the here document." 9 LimitString 10 #^^^^Indented limit string. Error! This script will not behave as expected. 11 12 echo "----------------------------------------------------------------------" 13 14 # These comments are outside the 'here document', 15 #+ and should not echo. 16 17 echo "Outside the here document." 18 19 exit 0 20 21 echo "This line had better not echo." # Follows an 'exit' command.</PRE></TD></TR></TABLE> </P></TD></TR></TABLE></DIV><P>For those tasks too complex for a <SPANCLASS="QUOTE">"here document"</SPAN>, consider using the <BCLASS="COMMAND">expect</B> scripting language, which is specifically tailored for feeding input into interactive programs.</P><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="AEN13393">17.1. Here Strings</A></H1><P><ANAME="HERESTRINGSREF"></A></P><P>A <ICLASS="EMPHASIS">here string</I> can be considered as a stripped-down form of <ICLASS="EMPHASIS">here document</I>. It consists of nothing more than <BCLASS="COMMAND">COMMAND <<<$WORD</B>, where <TTCLASS="VARNAME">$WORD</TT> is expanded and fed to the <TTCLASS="FILENAME">stdin</TT> of <TTCLASS="VARNAME">COMMAND</TT>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="PREPENDEX"></A><P><B>Example 17-13. Prepending a line to a file</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # prepend.sh: Add text at beginning of file. 3 # 4 # Example contributed by Kenny Stauffer, 5 #+ and slightly modified by document author. 6 7 8 E_NOSUCHFILE=65 9 10 read -p "File: " file # -p arg to 'read' displays prompt. 11 if [ ! -e "$file" ] 12 then # Bail out if no such file. 13 echo "File $file not found." 14 exit $E_NOSUCHFILE 15 fi 16 17 read -p "Title: " title 18 cat - $file <<<$title > $file.new 19 20 echo "Modified file is $file.new" 21 22 exit 0 23 24 # from 'man bash': 25 # Here Strings 26 # A variant of here documents, the format is: 27 # 28 # <<<word 29 # 30 # The word is expanded and supplied to the command on its standard input.</PRE></TD></TR></TABLE><HR></DIV><P>Exercise: Find other uses for <ICLASS="EMPHASIS">here strings</I>.</P></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="redirapps.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="recess-time.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Applications</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="part3.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Recess Time</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -