#!/bin/bash
###########################################################################
#
# Shell program to create a shell script template.
#
# Copyright © 1998-2002, William Shotts, Jr.
# <bshotts@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# This software is part of the LinuxCommand.org project, a site for
# Linux education and advocacy devoted to helping users of legacy
# operating systems migrate into the future.
#
# You may contact the LinuxCommand.org project at:
#
# http://www.linuxcommand.org
#
# Description:
#
# This program writes a shell script template to a file.
# It can be used within a text editor (for example, Nedit) to
# begin a new shell script file. If the "-i" option is used, the
# program will prompt the user for various things used to further
# develop the script. It will construct the help instructions
# automatically, the usage message, and the mechanism used to
# process the command line options and arguments.
#
# Usage:
# new_script [ -h | --help ] [ [ -i ] [ -f file ] ]
#
# Options:
#
# -h, --help Display this help message and exit.
# -i Prompt user for script information. This
# includes a one line description of the
# script, its command line options and
# arguments.
# -f file Write output to file, otherwise output
# is written to standard output.
#
# Revisions:
#
# 01/05/1998 File created
# 07/08/1998 Added a lot of common functions
# 11/06/1998 Added code to generate author's name
# 06/25/1999 Improved comments
# 09/13/1999 Cosmetic improvements
# 12/05/1999 Added command line argument support
# 12/24/1999 Added -i, -f, -h support
# 01/11/2000 Cosmetic improvements
# 01/29/2000 Expanded GNU license text
# 02/09/2000 Added email address and support for command
# line options (2.0.0)
# 03/12/2000 Cosmetic improvements (2.0.1)
# 03/23/2000 Added CVS ID and linuxcommand.org message (2.0.2)
# 06/17/2000 Fixed problem in helptext where here script token
# was being ignored. (2.0.3)
# 06/28/2000 Added call to clean_up if invalid option is given
# (2.0.4) From bug report by Bryan <bryan@eburg.com>.
# 06/30/2000 Added root user detection and improved temp file
# handling. (2.0.5) Improvments suggested by
# Tomi Ollila <Tomi.Ollila@sonera.com>
# jura@geekpitlabs.com
# 08/03/2000 Further improvements to temp file handling and
# other cosmetic fixes. (2.0.6)
# 02/10/2002 Improved signal handling in output script,
# "restyled" comments in output script and improved
# user interface. (2.1.0)
#
# $Id: new_script,v 1.5 2002/02/11 00:18:15 bshotts Exp $
###########################################################################
###########################################################################
# Constants and Global Variables
###########################################################################
PROGNAME=$(basename $0)
VERSION="2.1.0"
SCRIPTSHELL=${SHELL}
DEFAULT_SCRIPT_NAME=untitled_script
if [ -d ~/tmp ]; then
TEMP_DIR=~/tmp
else
TEMP_DIR=/tmp
fi
TEMP_FILE=$(mktemp -q "${TEMP_DIR}/${PROGNAME}.$$.XXXXXX")
# Make some pretty date strings
DATE=$(date +'%m/%d/%Y')
YEAR=$(date +'%Y')
# Get user's real name from passwd file
AUTHOR=$(awk -v USER=$USER 'BEGIN { FS = ":" } $1 == USER { print $5 }' < /etc/passwd)
# Construct the user's email address from the hostname (this works in
# RH Linux, but not in Solaris) or the REPLYTO environment variable, if defined
EMAIL_ADDRESS="<${REPLYTO:-${USER}@$(hostname)}>"
# Bring forth a few global variables
purpose="(describe purpose of script)"
root_user=
root_check=
security_considerations=
###########################################################################
# Functions
###########################################################################
function clean_up
{
#####
# Function to remove temporary files and other housekeeping
# No arguments
#####
rm -f ${TEMP_FILE}
}
function graceful_exit
{
#####
# Function called for a graceful exit
# No arguments
#####
clean_up
exit
}
function error_exit
{
#####
# Function for exit due to fatal program error
# Accepts 1 argument
# string containing descriptive error message
#####
local err_msg
err_msg="${PROGNAME}: ${1}"
echo ${err_msg} >&2
clean_up
exit 1
}
function term_exit
{
#####
# Function to perform exit if termination signal is trapped
# No arguments
#####
echo "${PROGNAME}: Terminated"
clean_up
exit
}
function int_exit
{
#####
# Function to perform exit if interrupt signal is trapped
# No arguments
#####
echo "${PROGNAME}: Aborted by user"
clean_up
exit
}
function usage
{
#####
# Function to display a usage message (does not exit)
# No arguments
#####
echo "Usage: ${PROGNAME} [-h | --help] | [ [-i] [-f file] ]"
}
function helptext
{
#####
# Function to display help message for program
# No arguments
#####
local tab=$(echo -en "\t\t")
cat <<- _EOF_
${PROGNAME} ver. ${VERSION}
This program creates a template for a shell program.
$(usage)
Options:
-h, --help Display this help message and exit.
-i Interactive mode. Prompt user for
${tab}script information.
-f file Write output to file, otherwise write
${tab}output to standard output.
_EOF_
}
function comment_bar_long
{
#####
# Function to output a long comment bar
# No arguments
#####
echo "# -------------------------------------------------------------------"
}
function comment_bar_short
{
#####
# Function to output a short comment bar
# No arguments
#####
echo "# -----"
}
function comment_text
{
#####
# Function to output a comment string
# Arguments:
# 1 comment string (optional)
#####
if [ -z "$1" ]
then
echo "#"
else
echo -e "#\t$1"
fi
}
function set_shell
{
#####
# Function to output first line of script indicating command interpreter
# No arguments
#####
echo -e "#!${SCRIPTSHELL}\n"
}
function section_header
{
#####
# Function to output section header comment block
# Arguments:
# 1 comment string (optional)
#####
echo -e "\n"
comment_bar_long
comment_text "$1"
comment_bar_long
}
function ask_yes_no
{
#####
# Function to ask a yes/no question
# Arguments:
# 1 prompt string (optional)
#####
local yn=
while [ "$yn" = "" ]; do
echo -en "$1"
read yn
case $yn in
y|Y) yn=0 ;;
n|N) yn=1 ;;
*) yn=
echo "Invalid response - please answer y or n"
;;
esac
done
return $yn
}
function script_header
{
#####
# Function to output script header comment block
# Arguments:
# 1 name of output file (optional)
#####
local output_file=$(basename ${1-$DEFAULT_SCRIPT_NAME})
set_shell
comment_bar_long
comment_text
comment_text "Shell program to ${purpose}."
comment_text
comment_text "Copyright ${YEAR}, ${AUTHOR} ${EMAIL_ADDRESS}."
comment_text
comment_text "This program is free software; you can redistribute it and/or"
comment_text "modify it under the terms of the GNU General Public License as"
comment_text "published by the Free Software Foundation; either version 2 of the"
comment_text "License, or (at your option) any later version. "
comment_text
comment_text "This program is distributed in the hope that it will be useful, but"
comment_text "WITHOUT ANY WARRANTY; without even the implied warranty of"
comment_text "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU"
comment_text "General Public License for more details."
comment_text
comment_text "Description:"
comment_text
comment_text
if [ "${root_user}" != "" ]; then
comment_text "${root_user}"
fi
if [ "${security_considerations}" != "" ]; then
comment_text "${security_considerations}"
fi
comment_text
comment_text "Usage:"
comment_text
comment_text " ${output_file} [ -h | --help ]${opt_usage}"
comment_text
comment_text "Options:"
comment_text
comment_text " -h, --help Display this help message and exit."
echo -en "${opt_comment}"
comment_text
comment_text
comment_text "Revision History:"
comment_text
comment_text "${DATE} File created by new_script ver. $VERSION"
comment_text
comment_bar_long
}
function get_option_name
{
#####
# Prompt user for name of command option
# Returns option name (via stdout)
# Arguments:
# 1 option number (required)
#####
# Fatal error if required arguments are missing
if [ "$1" = "" ]; then
error_exit "get_option_name: missing argument 1"
fi
local foo
while true; do
echo -en "\nName of option ${1} [a-z] (return to quit): "
read foo
# If response is empty return empty opt_name. We are done with options.
if [ "$foo" = "" ]; then
opt_name=""
return
else
# Otherwise verify opt_name
opt_name=$(echo $foo | awk '/^[a-gi-z]$/ { print $0 }')
if [ "$opt_name" != "" ]; then
break
else
echo "Invalid response. Option must be single lowercase letter except 'h'."
fi
fi
done
# Get description of option
echo -en "Description of option '${opt_name}': "
read opt_desc
# Get argument for option if required
echo -en "Does option '${opt_name}' require an argument (like a file name) [y/n] -> "
read foo
if [ "$foo" = "y" ]; then
arg_name=""
while [ "$arg_name" = "" ]; do
echo -en "Name of argument for option '${opt_name}': "
read arg_name
done
opt_opt="${opt_opt}${opt_name}:"
else
arg_name=""
opt_opt="${opt_opt}${opt_name}"
fi
if [ "$arg_name" = "" ]; then
opt_usage="${opt_usage} [-${opt_name}]"
else
opt_usage="${opt_usage} [-${opt_name} ${arg_name}]"
fi
} # end of get_option_name
function interactive_prompting
{
#####
# Prompt user for script information
# Arguments:
# none
#####
local opt_count
echo -en "Purpose of this script is to: "
read purpose
if ask_yes_no "Does this script require superuser privileges to run? [y/n] --> "; then
root_user="NOTE: You must be the superuser to run this script."
root_check="root_check"
fi
if ask_yes_no "Does this script contain security information? [y/n] ---------> "; then
security_considerations="WARNING!: Contains security info. Do not set world-readable."
fi
opt_opt=":h"
if ask_yes_no "\nDoes this script have command line options? [y/n] ------------> "; then
opt_count=1
# While there are options let's ask the user about them
while [ $opt_count -gt 0 ]; do
get_option_name $opt_count
# If user just hits return, that means we are done asking about options
if [ "$opt_name" != "" ]; then
opt_comment="${opt_comment}$(printf "#\\\t\\\t%-4s%-12s%s\\\n" "-${opt_name}" "${arg_name}" "$opt_desc")"
opt_help="${opt_help}$(printf "\\\t%-4s%-12s%s\\\n" "-${opt_name}" "${arg_name}" "$opt_desc")"
if [ "$arg_name" = "" ]; then
opt_case="${opt_case}$(printf "\\\t\\\t%1s )\\\techo \"%s\" ;;\\\n" "${opt_name}" "${opt_desc}")"
else
opt_case="${opt_case}$(printf "\\\t\\\t%1s )\\\techo \"%s - argument = %s\" ;;\\\n" "${opt_name}" "${opt_desc}" "\$OPTARG")"
fi
opt_count=$((opt_count + 1))
else
opt_count=0
fi
done
fi
} # end of interactive_prompting
function write_program
{
#####
# Function to write body of program to stdout
# 1 argument (optional)
# name of output file
#####
script_header $1
# Create constants section
section_header "Constants"
cat << _EOF_
PROGNAME=\$(basename \$0)
VERSION="0.0.1"
_EOF_
# Create functions section and define common functions
section_header "Functions"
##########################################################
### PAY ATTENTION! WHAT FOLLOWS IS NOT PART OF THIS SCRIPT
### START OF "HERE" SCRIPT
##########################################################
cat << _EOF_
function clean_up
{
# -----------------------------------------------------------------------
# Function to remove temporary files and other housekeeping
# No arguments
# -----------------------------------------------------------------------
rm -f \${TEMP_FILE1}
}
function error_exit
{
# -----------------------------------------------------------------------
# Function for exit due to fatal program error
# Accepts 1 argument:
# string containing descriptive error message
# -----------------------------------------------------------------------
echo "\${PROGNAME}: \${1:-"Unknown Error"}" >&2
clean_up
exit 1
}
function graceful_exit
{
# -----------------------------------------------------------------------
# Function called for a graceful exit
# No arguments
# -----------------------------------------------------------------------
clean_up
exit
}
function signal_exit
{
# -----------------------------------------------------------------------
# Function to handle termination signals
# Accepts 1 argument:
# signal_spec
# -----------------------------------------------------------------------
case \$1 in
INT) echo "\$PROGNAME: Program aborted by user" >&2
clean_up
exit
;;
TERM) echo "\$PROGNAME: Program terminated" >&2
clean_up
exit
;;
*) error_exit "\$PROGNAME: Terminating on unknown signal"
;;
esac
}
function make_temp_files
{
# -----------------------------------------------------------------------
# Function to create temporary files
# No arguments
# -----------------------------------------------------------------------
# Use user's local tmp directory if it exists
if [ -d ~/tmp ]; then
TEMP_DIR=~/tmp
else
TEMP_DIR=/tmp
fi
# Temp file for this script, using paranoid method of creation to
# insure that file name is not predictable. This is for security to
# avoid "tmp race" attacks. If more files are needed, create using
# the same form.
TEMP_FILE1=\$(mktemp -q "\${TEMP_DIR}/\${PROGNAME}.\$\$.XXXXXX")
if [ "\$TEMP_FILE1" = "" ]; then
error_exit "cannot create temp file!"
fi
}
function usage
{
# -----------------------------------------------------------------------
# Function to display usage message (does not exit)
# No arguments
# -----------------------------------------------------------------------
echo "Usage: \${PROGNAME} [-h | --help]${opt_usage}"
}
function helptext
{
# -----------------------------------------------------------------------
# Function to display help message for program
# No arguments
# -----------------------------------------------------------------------
local tab=\$(echo -en "\t\t")
cat <<- -EOF-
\${PROGNAME} ver. \${VERSION}
This is a program to ${purpose}.
\$(usage)
Options:
-h, --help Display this help message and exit.
$(echo -en "${opt_help}")
${root_user}
${security_considerations}
-EOF-
}
_EOF_
##########################################################
### END OF "HERE" SCRIPT
##########################################################
if [ "$root_check" = "root_check" ]; then
cat << _EOF_
function root_check
{
#####
# Function to check if user is root
# No arguments
#####
if [ "\$(id | sed 's/uid=\\([0-9]*\\).*/\\1/')" != "0" ]; then
error_exit "You must be the superuser to run this script."
fi
}
_EOF_
fi
# Create main section and set up traps
section_header "Program starts here"
##########################################################
### PAY ATTENTION! WHAT FOLLOWS IS NOT PART OF THIS SCRIPT
### START OF "HERE" SCRIPT
##########################################################
cat << _EOF_
##### Initialization And Setup #####
# Set file creation mask so that all files are created with 600 permissions.
umask 066
$root_check
# Trap TERM, HUP, and INT signals and properly exit
trap "signal_exit TERM" TERM HUP
trap "signal_exit INT" INT
# Create temporary file(s)
make_temp_files
##### Command Line Processing #####
if [ "\$1" = "--help" ]; then
helptext
graceful_exit
fi
while getopts "$opt_opt" opt; do
case \$opt in
$(echo -en "${opt_case}")
h ) helptext
graceful_exit ;;
* ) usage
clean_up
exit 1
esac
done
##### Main Logic #####
graceful_exit
_EOF_
##########################################################
### END OF "HERE" SCRIPT
##########################################################
}
###########################################################################
# Program starts here
###########################################################################
# Trap TERM, HUP, and INT signals and properly exit
trap term_exit TERM HUP
trap int_exit INT
# Process command line arguments
if [ "$1" = "--help" ]; then
helptext
graceful_exit
fi
file_flag=0
interactive_flag=0
while getopts ":hif:" opt; do
case $opt in
f ) file_flag=1
output_file=${OPTARG}
;;
i ) interactive_flag=1
;;
h ) helptext
graceful_exit
;;
* ) usage
exit 1
esac
done
if [ $file_flag = 1 ] ; then
# See if output file already exists
if [ -e "${output_file}" ] ; then
# Make sure it's a regular file
if [ -f "${output_file}" ] ; then
# Is it writable?
if [ -w "${output_file}" ]; then
# Confirm overwrite
if ! ask_yes_no "Output file exists - Overwrite? [y/n] "; then
int_exit
fi
else
error_exit "Output file is not writable"
fi
else
error_exit "Output file is not a regular file"
fi
else
# Try and write it
touch "${output_file}" || error_exit "Cannot write output file"
chmod 700 "${output_file}" || error_exit "Unable to set permissions on output file"
fi
if [ $interactive_flag = 1 ]; then
interactive_prompting
fi
write_program $output_file > $output_file
else
if [ $interactive_flag = 1 ]; then
interactive_prompting
fi
write_program
fi
graceful_exit
syntax highlighted by Code2HTML, v. 0.9.1