123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- #! /bin/bash
- # Script to print "some" lines of a file, like head or tail but, random start
- #
- # Usage: some [[-#] FILE]
- set -e; set -u; set -o pipefail # be safe out there
- # Helper functions
- PROG=`basename "$0" | tr -d '\n'`
- function info() { echo `date +%c` ${PROG}\: info: "$@" 1>&2; }
- function warn() { echo `date +%c` ${PROG}\: warning: "$@" 1>&2; }
- function error() { echo `date +%c` ${PROG}\: error: "$@" 1>&2; }
- function debug() { [[ -v DEBUG ]] && echo `date +%c` ${PROG}\: debug: "$@" 1>&2 || true ; }
- function die() { echo `date +%c` ${PROG}\: fatal: "$@" 1>&2 && exit 1; }
- function truncate() {
- # trunchate a FILE to MAXLINES
- local FILE=$1
- local MAXLINES=$2
- local TEMP=`mktemp`
- cp ${FILE} ${TEMP} && \
- tail -${MAXLINES} ${TEMP} > \
- ${FILE} && \
- rm ${TEMP}
- }
- function someLines {
- # Functon to print "some" lines of a file, like head or tail but, random start
- #
- # ARGS:
- #
- # $1 - "-#" or FILENAME if only one arg
- # $2 - FILENAME if present
- local FILE=$1
- local HOW_MANY=$2
- # Count the lines to bound display
- LINES=`wc -l $FILE | sed -e 's/ .*//'`
- # TODO Do something sensible for stdin here
- # Either
- # - Save /dev/stdin to a tmp file (up to a max?), count THAT and use as FILE
- # - revert to head-like behavior (with a timeout?) (since we have no idea how long stdin is)
- # pick a random starting line at least HOW_MANY back from the end
- FIRST=$((1 + RANDOM % (LINES - HOW_MANY + 1)))
- FIRST=$((FIRST>LINES ? LINES : FIRST))
- LAST=$((FIRST + HOW_MANY - 1))
- LAST=$((LAST>LINES ? LINES : LAST))
- # log line numbers to allow re-extraction of randomly chosen lines
- info lines $FIRST to $LAST \(of $LINES\) of `readlink -f $FILE` |& cat >> ${SOMELOG}
- # only keep MAXLOG lines of SOMELOG
- truncate $SOMELOG $MAXLOG
- # Lets see some lines !
- awk "NR >= $FIRST && NR <= $LAST" $FILE
- }
- function usage() {
- if [ "$1" != "" ]; then
- # TODO allow for undefined $1. Now, have to set to "" or get undefined error.
- warn "${1}"
- fi
- USAGE=$(cat <<-END
- Usage: $PROG [options] [FILENAME]
- Print some random lines from a file
- options:
- -# The number of lines to print. Default 10.
- -h Print usage.
- arguments:
- FILENAME The file to sample. Default /dev/stdin
- END
- )
- info "$USAGE"
- }
- function main() {
- # main - parse args, set defaults, call someLines
- # Bash Version 3 required (it also works with ksh)
- [[ ${BASH_VERSINFO[0]} -lt 3 ]] && exit 1
- # Defaults
- local HOW_MANY=10 # Number of lines to print. Default.
- local SOMELOG="${HOME}/.somelog" # log of queries in case you want to find that chunk again
- local MAXLOG=10
- # Put all arguments in a new array (because BASH_ARGV is read only)
- ARGS=( "$@" )
- for i in "${!ARGS[@]}"; do
- case "${ARGS[i]}" in
- '') # Skip if element is empty (happens when its unsetted before)
- continue
- ;;
- -[0-9]*) # Use +1 to access next array element and unset it
- HOW_MANY="${ARGS[i]}"
- HOW_MANY=`echo $HOW_MANY | sed 's/^-//'`
- shift
- ;;
- -h) # Use +1 to access next array element and unset it
- usage ""
- exit 0
- ;;
- --) # End of arguments
- unset 'ARGS[i]'
- break
- ;;
- *) # Skip unset if our argument has not been matched
- continue
- ;;
- esac
- unset 'ARGS[i]'
- done
- # TODO add -n argumet to print line numbers
- FILE=${1:-"/dev/stdin"}
- if [ "$#" -gt 1 ]; then
- usage "Too many arguments"
- exit 1
- fi
- someLines $FILE $HOW_MANY
- }
- main $*
|