Improved Connoisseur's Shar

ajs ajs at hpfcla.UUCP
Fri Dec 28 07:32:00 AEST 1984


[Posted for someone else, by request, because mod.sources is not yet
 reaching many sites.  Please respond to address below, not to ajs.]

Here's the latest "Connoisseur's shar" and documentation.  Actually, it's an
upgrade to the Conn. Shar originally posted to net.sources a few months ago.
It runs on both Berkeley and Bell Unixes.  It has a few advantages over the
previously-posted version:

1.  You can archive a whole directory subtree via:  shar `find dir -print`
2.  The original file's permissions/modes are duplicated upon unpacking.
3.  The EOF marker is guaranteed to be unique from what's in the archive files.
4.  A timestamp and personstamp is recorded in the archive.
5.  Lines beginning with characters that mailers don't like (tildes, dots,
	ampersands) are no longer dangerous.
6.  The table-of-contents line no longer overflows your mailer's maximum line.

These features also make this a candidate for being dubbed "The Glutton's Shar"
since it takes longer to start up.  The way to fix that would be to rewrite it
in C, but that seems to take away some of its novelty.  Still, a C version may
be forthcoming (especially if someone volunteers!)....

Kudos to Dan Hoey <hoey at NRL-AIC.ARPA>, who contributed immensely to shar's
current feature set, especially the directory-recursing code.  A tip of the
Hatlo hat also to Alan Silverstein, who set shar's clear coding style and fixed
bugs in earlier versions, and who posted this for me since I don't have write-
access to the Usenet.

Bob Desinger
ucbvax!hpda!bd		hpda!bd at BERKELEY	ihnp4!hpfcla!hpda!bd
Hewlett-Packard Co.	11000 Wolfe Road	Cupertino, CA  95014

----------

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# shar shar.1

echo x - shar
cat > "shar" << '//E*O*F shar//'

# UNISRC_ID: @(#)shar.sh	26.2	84/09/06  
: Make a shell archive package

# Usage: $0 [-b] [-c] [-t] [-v] files... > package
# See the manual entry for details.


# Initialize:

	diagnostic='eval echo >&2'	# diagnostics to stderr by default.
	trap '$diagnostic "$0: quitting early"; exit 1' 1 2 3 15

	base_option=FALSE		# use pathnames, not basenames.
	check_option=FALSE		# don't generate integrity check.
	usage='Usage: $0 \[-b] \[-c] \[-t] \[-v] files... \> package'


# Extract and digest options, if any:
#
# Un-comment the "-)" line below to treat single dashes as a no-op.
# Commented means single dashes elicit a usage diagnostic.

    while [ -n "$1" ]	# while there are more arguments,
    do			# digest them; stop when you find a non-option.
	case "$1" in
	-[bB])	base_option=TRUE;				shift ;;
	-[cC])	check_option=TRUE;				shift ;;
	-[tT])	verbose=TRUE; diagnostic='eval echo >/dev/tty';	shift ;;
	-[vV])	verbose=TRUE;					shift ;;
    ##	-)	shift ;;			# eat single dashes.
	-*)	$diagnostic $usage; exit 1 ;;	# die at illegal options.
	*)	break ;;
	esac
    done


# Check remaining arguments, which should be just a list of files:

	if [ $# = 0 ]
	then			# no arguments left!
	    $diagnostic $usage
	    exit 1
	fi


# Emit the prologue, then check and list ingredients:
# (The leading newline is for those who type csh instead of sh.)

	cat <<\!!!

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
!!!

	contents=''				# no files so far.

	for arg					# for all files specified,
	do					# establish archive name.
	    if [ -f "$arg" ]			# non-directory and exists.
	    then
		case $base_option in
		TRUE)	unpack_name=`basename "$arg"`	;;
		FALSE)	unpack_name="$arg"		;;
		esac

		contents="$contents $unpack_name"

	    else
		$diagnostic "$0: cannot archive $arg"
		exit 1
	    fi
	done

	echo "#$contents"
	echo


# Emit the files and their separators:

	for arg		# for all arguments left (file names).
	do
	    case $base_option in

	    TRUE)   unpack_name=`basename "$arg"`
		    test $verbose \
		      && $diagnostic "a - $unpack_name [from $arg]" ;;

	    FALSE)  unpack_name="$arg"
		    test $verbose && $diagnostic "a - $arg" ;;
	    esac

	    separator="//E*O*F $unpack_name//"
	    echo "echo x - $unpack_name"
	    echo "cat > \"$unpack_name\" << '$separator'"
	    cat "$arg"
	    echo $separator
	    echo
	done


# If the -c option was given, emit the checking epilogue:
# (The sed script converts files to basenames so it works regardless of -b.)

	if [ $check_option = TRUE ]
	then
	    echo "echo Possible errors detected by \'wc\' [hopefully none]:"
	    echo 'temp=/tmp/shar$$'
	    echo 'trap "rm -f $temp; exit" 0 1 2 3 15'	# will clean up.
	    echo 'cat > $temp <<\!!!'
	    wc $@ | sed 's=[^ ]*/=='
	    echo '!!!'
	    echo "wc $contents | sed 's=[^ ]*/==' | "'diff -b $temp -'
	fi


# Finish up:

	echo 'exit 0'		# sharchives unpack even if junk follows.
	exit 0
//E*O*F shar//

echo x - shar.1
cat > "shar.1" << '//E*O*F shar.1//'
.TH SHAR 1 HEWLETT-PACKARD
.ad b
.SH NAME
shar \- make a shell archive package
.SH SYNOPSIS
\fBshar\fR [\fB-b\fR] [\fB-c\fR] [\fB-t\fR] [\fB-v\fR] \fIfiles...\fR
.SH DESCRIPTION
.I Shar
bundles the named
.IR file ( s )
into a single distribution package suitable for mailing or carrying around.
The files should be themselves mailable, e.g. not object code.
.IR Shar 's
resulting package, written to standard output, is an editable ASCII file.
It is actually a shell script which uses \fIsh\fR\^(1) "here" documents to
extract its contents into appropriate places.
.PP
The package is unwrapped by running \fIsh\fR\^(1) with the package name as an
argument.
Its files are written to the pathnames recorded in the archive.
.PP
Available options are:
.TP
.B \-b
Archive files under their basenames, regardless of the original pathnames
specified.
The contents are thus unpacked into the current directory instead of to the
originally-specified pathnames.
This allows you to archive files from many directories but unpack them into a
single directory.
It also allows you to unpack, say,
.I /etc/termcap
into
.I ./termcap
instead of overwriting the original one in
.IR /etc .
.TP
.B \-c
Cause
.I shar
to append to the package a simple data-integrity check using
.I wc
to insure that the contents were not damaged in transit.
This check is performed automatically after unpacking.
.TP
.B \-t
Write diagnostics and messages directly to
.IR /dev/tty ,
your terminal, instead of to standard error.
This is useful when invoking
.I shar
from programs such as
.I vi
which normally combine standard error with standard output.
Specifying 
.B \-t
also turns on the
.B \-v
(verbose) option.
.TP
.B \-v
Announce archived file names as they are packed.
The
.B \-t
option affects where these announcements go.
.SH FILES
/dev/tty    	if specified by the \fB-t\fR option
.br
/tmp/shar*  	used for the insurance check after unpacking
.br
cat, echo   	as subprocesses
.br
basename, wc	as optional subprocesses
.SH DIAGNOSTICS
.I Shar
refuses to archive nonexistent files and directories.
It terminates and does no archiving if it encounters them.
.PP
Exit status 1 is returned upon interrupt or trouble with arguments.
.SH "SEE ALSO"
ar(1),
basename(1),
cat(1),
cpio(1),
echo(1),
sh(1),
tar(1),
wc(1).
.SH BUGS
Ownerships and permissions for archived files are not retained.
.PP
The integrity check is very simple-minded.
In particular, it only notices if the number of characters, words, or lines is
altered.
It fails to catch bits flipped during transmission.
.PP
There should be a way to archive directories by name instead of using arguments
such as
.IR dir/* .
//E*O*F shar.1//

echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/$0$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
    123    480   3083 shar
     99    425   2644 shar.1
    222    905   5727 total
!!!
wc  shar shar.1 | sed 's=[^ ]*/==' | diff -b $temp -
exit 0



More information about the Comp.sources.unix mailing list