Skip to content

Instantly share code, notes, and snippets.

@wgzhao
Created December 29, 2011 14:36
Show Gist options
  • Save wgzhao/1534358 to your computer and use it in GitHub Desktop.
Save wgzhao/1534358 to your computer and use it in GitHub Desktop.
shell here document usage sample
#!/bin/bash
# generate-script.sh
# Based on an idea by Albert Reiner.
OUTFILE=generated.sh # Name of the file to generate.
# -----------------------------------------------------------
# 'Here document containing the body of the generated script.
(
cat < <'EOF'
#!/bin/bash
echo "This is a generated shell script."
# Note that since we are inside a subshell,
#+ we can't access variables in the "outside" script.
echo "Generated file will be named: $OUTFILE"
# Above line will not work as normally expected
#+ because parameter expansion has been disabled.
# Instead, the result is literal output.
a=7
b=3
let "c = $a * $b"
echo "c = $c"
exit 0
EOF
) > $OUTFILE
# -----------------------------------------------------------
# Quoting the 'limit string' prevents variable expansion
#+ within the body of the above 'here document.'
# This permits outputting literal strings in the output file.
if [ -f "$OUTFILE" ]
then
chmod 755 $OUTFILE
# Make the generated file executable.
else
echo "Problem in creating file: \"$OUTFILE\""
fi
# This method can also be used for generating
#+ C programs, Perl programs, Python programs, Makefiles,
#+ and the like.
exit 0
#!/bin/bash
# A 'cat' here-document, but with parameter substitution disabled.
NAME="John Doe"
RESPONDENT="the author of this fine script"
cat < <'Endofmessage'
Hello, there, $NAME.
Greetings to you, $NAME, from $RESPONDENT.
Endofmessage
# No parameter substitution when the "limit string" is quoted or escaped.
# Either of the following at the head of the here document would have
#+ the same effect.
# cat <<"Endofmessage"
# cat <<\Endofmessage
exit
#!/bin/bash
# Another 'cat' here document, using parameter substitution.
# Try it with no command-line parameters, ./scriptname
# Try it with one command-line parameter, ./scriptname Mortimer
# Try it with one two-word quoted command-line parameter,
# ./scriptname "Mortimer Jones"
CMDLINEPARAM=1 # Expect at least command-line parameter.
if [ $# -ge $CMDLINEPARAM ]
then
NAME=$1 # If more than one command-line param,
#+ then just take the first.
else
NAME="John Doe" # Default, if no command-line parameter.
fi
RESPONDENT="the author of this fine script"
cat <
#!/bin/bash
# commentblock.sh
: <<COMMENTBLOCK
echo "This line will not echo."
This is a comment line missing the "#" prefix.
This is another comment line missing the "#" prefix.
&*@!!++=
The above line will cause no error message,
because the Bash interpreter will ignore it.
COMMENTBLOCK
echo "Exit value of above \"COMMENTBLOCK\" is $?." # 0
# No error shown.
echo
# The above technique also comes in useful for commenting out
#+ a block of working code for debugging purposes.
# This saves having to put a "#" at the beginning of each line,
#+ then having to go back and delete each "#" later.
# Note that the use of of colon, above, is optional.
echo "Just before commented-out code block."
# The lines of code between the double-dashed lines will not execute.
# ===================================================================
: <<DEBUGXXX
for file in *
do
cat "$file"
done
DEBUGXXX
# ===================================================================
echo "Just after commented-out code block."
exit 0
######################################################################
# Note, however, that if a bracketed variable is contained within
#+ the commented-out code block,
#+ then this could cause problems.
# for example:
#/!/bin/bash
: <<COMMENTBLOCK
echo "This line will not echo."
&*@!!++=
${foo_bar_bazz?}
$(rm -rf /tmp/foobar/)
$(touch my_build_directory/cups/Makefile)
COMMENTBLOCK
$ sh commented-bad.sh
commented-bad.sh: line 3: foo_bar_bazz: parameter null or not set
# The remedy for this is to strong-quote the 'COMMENTBLOCK' in line 49, above.
: <<'COMMENTBLOCK'
# Thank you, Kurt Pfeifle, for pointing this out.
#!/bin/bash
# here-function.sh
GetPersonalData ()
{
read firstname
read lastname
read address
read city
read state
read zipcode
} # This certainly looks like an interactive function, but...
# Supply input to the above function.
GetPersonalData <
或者可以像下面这种匿名功能一样:
#!/bin/bash
: <
#!/bin/bash
# self-document.sh: self-documenting script
# Modification of "colm.sh".
DOC_REQUEST=70
if [ "$1" = "-h" -o "$1" = "--help" ] # Request help.
then
echo; echo "Usage: $0 [directory-name]"; echo
sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATIONXX$/p' "$0" |
sed -e '/DOCUMENTATIONXX$/d'; exit $DOC_REQUEST; fi
: <<DOCUMENTATIONXX
List the statistics of a specified directory in tabular format.
---------------------------------------------------------------
The command-line parameter gives the directory to be listed.
If no directory specified or directory specified cannot be read,
then list the current working directory.
DOCUMENTATIONXX
if [ -z "$1" -o ! -r "$1" ]
then
directory=.
else
directory="$1"
fi
echo "Listing of "$directory":"; echo
(printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAME\n" \
; ls -l "$directory" | sed 1d) | column -t
exit 0
#!/bin/bash
# Noninteractive use of 'vi' to edit a file.
# Emulates 'sed'.
E_BADARGS=85
if [ -z "$1" ]
then
echo "Usage: `basename $0` filename"
exit $E_BADARGS
fi
TARGETFILE=$1
# Insert 2 lines in file, then save.
#--------Begin here document-----------#
vi $TARGETFILE <.
# Bram Moolenaar points out that this may not work with 'vim'
#+ because of possible problems with terminal interaction.
exit
#!/bin/bash
cat < <- HERE
include leading tab
include leading space
HERE
exit 0
#!/bin/bash
wall <
--------
@whiteorchid
Copy link

hi, dear author, for this script , heredoc-argsub.sh(the third one) I have tried and find the warning , is it not complete , thanks for your instructions , best wishes!

@gnanet
Copy link

gnanet commented Jan 9, 2020

@whiteorchid

hi, dear author, for this script , heredoc-argsub.sh(the third one) I have tried and find the warning , is it not complete , thanks for your instructions , best wishes!

Based on the description in the bottom of heredoc-argoff.sh, the opposite rule would ideally say, that if you have a non-quoted "limit string" then the parameter substitution will happen.

Also note that the heredoc-marker seems wrong in the body of the examples, but is correctly written in the bottom descriptions, so i assume, every occurrence of cat < < should be cat << without a space between the two <

That rule in mind, the heredoc-argsub.sh could be like below (i tested all three execution ways right now)

#!/bin/bash
# Another 'cat' here document, using parameter substitution.

# Try it with no command-line parameters,   ./scriptname
# Try it with one command-line parameter,   ./scriptname Mortimer
# Try it with one two-word quoted command-line parameter,
#                           ./scriptname "Mortimer Jones"

CMDLINEPARAM=1     #  Expect at least command-line parameter.

if [ $# -ge $CMDLINEPARAM ]
then
  NAME=$1          #  If more than one command-line param,
                   #+ then just take the first.
else
  NAME="John Doe"  #  Default, if no command-line parameter.
fi

RESPONDENT="the author of this fine script"

cat <<Endofmessage

Hello, there, $NAME.
Greetings to you, $NAME, from $RESPONDENT.

Endofmessage

# Parameter substitution works when the "limit string" is unquoted.

exit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment