簡單的 script,簡化日常跑程式順便要做 log 的步驟。目前是 FreeBSD only,除了各個 utility program,如 date、script 等路徑的關係之外,最重要的是 FreeBSD 上的 script 的 behavior 跟一般的 script 有些不一樣,允許直接把 command 放在 ${__out_file} 後面。另外,TCSH 的 time 也較精確,取得的資訊也較多,甚至可以在 .(t)cshrc 裡設定最後輸出格式 [1],所以下面就改成用 tcsh 做 time 了。

#!/bin/sh
# ----------------------------------------------------------------------------
# Amarganth Development Environment
# Copyright (C) 2004, Jeff Hung
# All rights reserved.
# ----------------------------------------------------------------------------
# $Date: 2006-09-12 12:37:52 +0800 (Tue, 12 Sep 2006) $
# $Rev: 3 $
# $Author: jeffhung $
# ----------------------------------------------------------------------------
# revid: "@(#) $Id: run.sh 3 2006-09-12 04:37:52Z jeffhung $"
# ----------------------------------------------------------------------------

__revision=`echo '$Rev: 3 $' | cut -d' ' -f2`;
__rev_date=`echo '$Date: 2006-09-12 12:37:52 +0800 (Tue, 12 Sep 2006) $' | cut -d' ' -f2`;

__usage()
{
	ex=$1;
	shift;
	echo >&2 "\
Usage: `basename $0` [ <option...> ] <command...>

Log, measure run-time, and review the execution of a given command.

Options:

    -b           Beep at end.  (default)
    -B           Disable -b option.
    -d           Delete the log file after completion.
    -D           Disable -d option.  (default)
    -e <enc>     Assume the output encoding of <command...> is <enc> and convert
                 back to the encoding specified by current locale using iconv(3)
                 when executing.
    -E           Disable -e option.
    -r           Review log file after completion. (default)
    -R           Disable -r option.
    -l <file>    Use log file <file> instead of auto-generated one.  (disable
                 -p option)
    -p <prefix>  Prefix of log file.  The default is '.run.' (relative to
                 current directory).
    -t           Append execution time information to output using TCSH
                 build-in time command, which is more precise. (default)
    -T           Disable -t option.

Example:

SHELL> `basename $0` ls -l

Revision: r${__revision} (${__rev_date})
";
	if [ $# -gt 0 ]; then
		echo >&2 "";
		echo >&2 "Error: $@";
	fi;
	exit $ex;
}

# Utility programs
__basename='basename';
__sed='sed';
__date='/bin/date';
__script='/usr/bin/script';
__tcsh='/bin/tcsh';
__time='time';
__less='/usr/bin/less';
__echo='echo';
__rm='rm';
__env='/usr/bin/env';
__iconv='iconv';

__opt_beep_at_end='yes';
__opt_out_encoding='';
__opt_del_log='no';
__opt_do_review='yes';
__opt_log_path='';
__opt_log_prefix='.run.';
__opt_log_time='yes';
while getopts bBdDe:ErRl:p:tT opt; do
	case $opt in
	b)	# Beep at end.  (default)
		__opt_beep_at_end='yes';
		;;
	B)	# Disable -b option.
		__opt_beep_at_end='no';
		;;
	d)	# Delete the log file after completion.
		__opt_del_log='yes';
		;;
	D)	# Disable -d option.  (default)
		__opt_del_log='no';
		;;
	e)	# Assume the output encoding of <command...> is <enc> and convert back
		# to the encoding specified by current locale using iconv(3) when
		# executing.
		__opt_out_encoding="${OPTARG}";
		;;
	E)	# Disable -e option.
		__opt_out_encoding='';
		;;
	r)	# Review log file after completion. (default)
		__opt_do_review='yes';
		;;
	R)	# Disable -r option.
		__opt_do_review='no';
		;;
	l)	# Use log file <file> instead of auto-generated one.  (disable -p
	    # option)
		__opt_log_path="${OPTARG}";
		;;
	p)	# Prefix of log file.  The default is '.run.' (relative to
		# current directory).
		__opt_log_prefix="${OPTARG}";
		;;
	t)	# Append execution time information to output using TCSH
		# build-in time command, which is more precise. (default)
		__opt_log_time='yes';
		;;
	T)	# Disable -t option.
		__opt_log_time='no';
		;;
	'?') # any other switch
		__usage 1 'Invalid argument: $opt';
		;;
	esac
done
shift `expr $OPTIND - 1`;

# Real command-line command
__pgm="$1";
__cmd="$@";

if [ "${__cmd}x" = "x" ]; then
	__usage 0;
fi;

__exe_name=`${__basename} $1 | ${__sed} 's/\.[^.]*\$//'`;
if [ -n "${__opt_log_path}" ]; then
	__out_file="${__opt_log_path}";
else
	__out_file=${__opt_log_prefix}${__exe_name}.`${__date} "+%Y%m%d-%H%M%S"`;
fi;
if [ "${__opt_log_time}x" = "yesx" ]; then
	__time_cmd="${__time} ";
else
	__time_cmd='';
fi;
if [ -z "${__opt_out_encoding}" ]; then
	__out_filter_cmd='';
else
	__out_filter_cmd="| ${__iconv} -f ${__opt_out_encoding}";
fi;

if [ "${HAVE_SCREEN_SHELLTITLE}x" != "x" ]; then
	printf '\033k\033\\%% %s \n\r' "$__pgm";
fi;

__start_time=`${__date} "+%Y-%m-%d %H:%M:%S"`;
${__script} -k -q -t 0 ${__out_file} \
	${__env} SHELL_AS_NOT_SHELL=yes \
	${__tcsh} -c "${__time_cmd}${__cmd}${__out_filter_cmd}";
__end_time=`${__date} "+%Y-%m-%d %H:%M:%S"`;
if [ "${__opt_do_review}x" = "yesx" ]; then
	${__echo} "";
	${__echo} "---------------------------------------------------------------";
fi;
${__echo} "" >> ${__out_file};
${__echo} "-[META]--------------------------------------------------------" >> ${__out_file};
${__echo} "Command    : ${__cmd}" >> ${__out_file};
${__echo} "Start Time : ${__start_time}" >> ${__out_file};
${__echo} "End Time   : ${__end_time}" >> ${__out_file};
if [ "${HAVE_SCREEN_SHELLTITLE}x" != "x" ]; then
	printf '\033k\033\\%% END:%s \n\r' "$__pgm";
fi;
if [ "${__opt_beep_at_end}x" = "yesx" ]; then
	printf '\a';
fi;
if [ "${__opt_do_review}x" = "yesx" ]; then
	${__less} -rfFM ${__out_file};
fi;
if [ "${__opt_del_log}x" = "yesx" ]; then
	${__rm} ${__out_file};
fi;

[1] 如在 .(t)cshrc 裡這樣下:

set time=(8 "\
Time spent in user mode   (CPU seconds) : %Us\
Time spent in kernel mode (CPU seconds) : %Ss\
Total time                              : %Es\
CPU utilisation (percentage)            : %P\
Times the process was swapped           : %W\
Times of major page faults              : %F\
Times of minor page faults              : %R")