#!/bin/bash show_usage() { echo echo ${0##/*}" Usage:" echo " Cut FIELDS from STRING using separator SEP" echo "${0##/} -fFIELDS -dSEP STRING" echo exit } case $1 in ""|"-h"|"--help") show_usage ;; esac # Minimum number of arguments needed by this program MINARGS=3 # count the number of arguments given COUNT=0 for ARGV in "$@" ; do (( COUNT++ )) ; done ARGC=$COUNT # [[ $DEBUG ]] && echo "ARGC=$COUNT" ##debug # check to make sure enough arguments were given if [[ $ARGC -lt $MINARGS ]] ; then [[ $DEBUG ]] && echo "Too few arguments given (Minimum:$MINARGS)" show_usage fi # Assign the variables to ARGV[?] COUNT=0 for ARGV in "$@" ; do (( COUNT++ )) ; declare ARG_${COUNT}="$ARGV" # [[ $DEBUG ]] && echo $ARG_$COUNT ##debug done # [[ $DEBUG ]] && echo "$ARG_1 $ARG_2 $ARG_3" ##debug # process_arguments # could use for ARGV_? in ARGC for WORD in "$@" ; do case $WORD in --) echo "End of arguments" ; shift ;; # --*) echo "Long option" ; shift ;; -*) true ; case $WORD in # -f=?) [[ $DEBUG ]] && echo "Short single FIELD Option using '='" # FIELDS=${WORD:3:1} FIELDS=${WORD##*=} [[ $DEBUG ]] && echo FIELDS=$FIELDS shift ;; -f=*|--fields=*) [[ $DEBUG ]] && echo "Short range FIELD Option using '='" # FIELDS=${WORD:3} FIELDS=${WORD##*=} [[ $DEBUG ]] && echo FIELDS=$FIELDS shift ;; -f?) [[ $DEBUG ]] && echo "Short single FIELD Option" #FIELDS=${WORD:2:1} FIELDS=${WORD##*f} [[ $DEBUG ]] && echo FIELDS=$FIELDS shift ;; -f) [[ $DEBUG ]] && echo "Short split FIELD Option" # if the next argument begins with a dash if [[ ${2:0:1} != "-" ]] ; then FIELDS=$2 [[ $DEBUG ]] && echo FIELDS=$FIELDS shift 2 else echo "Missing argument" exit fi ;; -f*) [[ $DEBUG ]] && echo "Short FIELD Option range" #FIELDS=${WORD:2} FIELDS=${WORD##*f} [[ $DEBUG ]] && echo FIELDS=$FIELDS shift ;; -d*) [[ $DEBUG ]] && echo "Short-short DEL Option" SEP=${WORD##*d} [[ $DEBUG ]] && echo SEP=$SEP shift ;; esac ;; esac done STRING="$@" [[ $DEBUG ]] && echo STRING="$@" ######### ignore() { if [[ $3 ]] ; then FIELDS=${1:2:1} SEP=${2:2:1} STRING=${3} else show_usage fi } #FIELD=$FIELDS #DEL=$SEP #STRING=$STRING # [[ $DEBUG ]] && echo FIELD=$FIELDS DEL=$SEP STRING=$STRING ################## # function _length counts the characters in a string and # echo the result. Requires PARSESTRING function _length() { COUNT=0 while [[ $PARSESTRING != "" ]] ; do # get the first remaining character FC=${PARSESTRING:0:1} # cut the first character PARSESTRING="${PARSESTRING#${FC}*}" (( COUNT++ )) done echo $COUNT } # example usage #PARSESTRING=$STRING #[[ $DEBUG ]] && echo STRINGLEN=$(_length $PARSESTRING) # function _freq counts the number of matches # of PATTERN in PARSESTRING and returns FREQ function _freq() { FREQ=0 ! [[ $PATTERN ]] && PATTERN=$1 ! [[ $PARSESTRING ]] && PARSESTRING=$2 while [[ $PARSESTRING != "" ]] ; do case $PARSESTRING in *$PATTERN*) FREQ=$(( FREQ + 1 )) ; PARSESTRING=${PARSESTRING#*${PATTERN}} ;; *) PARSESTRING="" ;; esac done echo $FREQ } # example usage #PARSESTRING=$STRING #PATTERN=$SEP #[[ $DEBUG ]] && echo "Found $(_freq) matches." # _freq $SEP $STRING # _print_field # print the contents of a single FIELD before the SEP in PARSESTRING # Requires/defaults: FIELD=$1 PATTERN=$2 PARSESTRING=$3 function _print_field() { FREQ=0 ! [[ $FIELD ]] && FIELD=$1 ! [[ $PATTERN ]] && PATTERN=$2 ! [[ $PARSESTRING ]] && PARSESTRING=$3 while [[ $PARSESTRING != "" ]] ; do case $PARSESTRING in *$PATTERN*) FREQ=$(( FREQ + 1 )) ; # echo FIELD_${FREQ}=${PARSESTRING%%${PATTERN}*} # declare FIELD_${FREQ}=${PARSESTRING%%${PATTERN}*} # [[ $DEBUG ]] && echo "FIELD_$FREQ=$FIELD_FREQ" if [[ $FIELD = $FREQ ]] ; then # echo FIELD_${FREQ}=${PARSESTRING%%${PATTERN}*} # right_of_first SEP STUB=${PARSESTRING#*${PATTERN}} # left_of_first SEP echo ${STUB%%${PATTERN}*} fi PARSESTRING=${PARSESTRING#*${PATTERN}} #echo $PARSESTRING ;; *) PARSESTRING="" ;; esac done } # example # _print_field $FIELD $SEP $STRING get_one_field() { if [[ $FIELD = 1 ]] ; then # output the contents to the left of the first SEP OUTPUT=${STRING%%${SEP}*} else # Chop off the first match and cheat on the count STUB=${STRING#*$SEP} COUNT=1 # skip over any matches before the requested one while [[ $COUNT -lt $(( $FIELD - 1 )) ]] ; do # ROF Chop off leading FIELD and/or SEP STUB=${STUB#*$SEP} [[ $DEBUG ]] && echo $STUB (( COUNT++ )) done # LOF Chop off trailing SEP and/or rest of STUB OUTPUT=${STUB%%${SEP}*} fi echo $OUTPUT } # examine the FIELDS variable and create a list of the chosen FIELDS # the first character is START or HEAD HEAD=${FIELDS:0:1} START=$HEAD # if the second character is a '-' then this is a range if [[ ${FIELDS:1:1} = "-" ]] ; then # if the third character is null, range goes to end of STRING if [[ ${FIELDS:2:1} = "" ]] ; then # this is an open START to END range echo "START to END range" START=${FIELDS:0:1} FINISH=$(_freq $SEP $STRING) FINISH=$(( FINISH + 1 )) # TAIL=${STRING#*$SEP} echo $START $FINISH $TAIL else # this is a closed range echo "closed range" START=${FIELDS:0:1} FINISH=${FIELDS:2:1} fi LIST="$START," COUNT=$START while [[ $COUNT -lt $(( $FINISH - 1 )) ]] ; do (( COUNT++ )) LIST=$LIST$COUNT"," done LIST=$LIST$FINISH echo LIST=$LIST elif [[ ${FIELDS:1:1} = "," ]] ; then # this is a list echo "FIELD list" LIST=$FIELDS echo LIST=$LIST elif [[ ${FIELDS:1:1} = "" ]] ; then # single argument given echo "single argument given" fi # readfirst character HEAD=${LIST:0:1} # chop the first digit and comma off the LIST LIST=${LIST:2} # echo the result ing HEAD echo HEAD=$HEAD # set the FIELD and get the contents FIELD=$HEAD echo FIELD=$HEAD is: $(get_one_field) while [[ $LIST != "" ]] ; do # readfirst character FIELD=${LIST:0:1} # chop the next digit and comma off the LIST LIST=${LIST:2} # echo the result echo FIELD=$FIELD is: $(get_one_field) done exit # code below here works okay ### case $FIELDS in ?-?) [[ $DEBUG ]] && echo "FIELDS is a closed (between) range" ! [[ $NEW_SEP ]] && NEW_SEP=$SEP START=${FIELDS:0:1} FINISH=${FIELDS:2:1} [[ $DEBUG ]] && echo "START=$START FINISH=$FINISH" MATCHES=0 FIELD=0 if [[ $START = 1 ]] ; then # increment the number of MATCHES (( MATCHES++ )) # OUTPUT is the contents of the FIELD to the left of the first SEP OUTPUT=${STRING%%$SEP*} # increment the FIELD pointer by one (( FIELD++ )) # by removing the first MATCH and SEP STUB=${STRING#*$SEP} echo "MATCH ($MATCHES) FIELD ($FIELD)" $OUTPUT # add NEW_SEP gonna move this... OUTPUT_STACK=$OUTPUT$NEW_SEP echo OUTPUT_STACK=$OUTPUT_STACK # increment the pointer by one FIELD # Chop off the first MATCH and SEP STUB=${STRING#*$SEP} echo STUB$FIELD=$STUB else # capture non-matching text # OUTPUT is the contents of the FIELD to the left of the first SEP OUTPUT=${STRING%%$SEP*} echo "Skipping FIELD 1 $OUTPUT" # increment the pointer by one FIELD (( FIELD++ )) STUB=${STRING#*$SEP} echo STUB$FIELD=$STUB fi echo # skip over any matches before the requested START FIELD while [[ $FIELD -lt $(( $START - 1 )) ]] ; do # this would be non-matching text # OUTPUT is the contents of the FIELD to the left of the first SEP OUTPUT=${STUB%%$SEP*} # increment the FIELD pointer (( FIELD++ )) # ROF Chop off leading FIELD and/or SEP STUB=${STUB#*$SEP} echo "Skipping FIELD:$FIELD $OUTPUT" echo STUB$FIELD=$STUB done echo if [[ $MATCHES = 0 ]] ; then # this is still START unless START=1 NO MATCHES yet #increment the FIELD pointer (( FIELD++ )) # OUTPUT is the contents of the FIELD to the left of the first SEP OUTPUT=${STUB%%${SEP}*} # increment the number of matches (( MATCHES++ )) echo "MATCH ($MATCHES) FIELD ($FIELD)" $OUTPUT # add NEW_SEP gonna move this... OUTPUT_STACK=$OUTPUT$NEW_SEP echo OUTPUT_STACK=$OUTPUT_STACK # ROF Chop off leading FIELD and/or SEP STUB=${STUB#*$SEP} echo STUB$FIELD=$STUB fi # end of HEAD while [[ $FIELD -lt $(( $FINISH )) ]] ; do # increment the FIELD pointer (( FIELD++ )) (( MATCHES++ )) # capture the FIELD contents OUTPUT="$(get_one_field)" echo "FIELD ($FIELD) MATCH ($MATCHES) $OUTPUT" # ROF Chop off leading FIELD and/or SEP STUB=${STUB#*$SEP} echo STUB$FIELD=$STUB # add the current OUPUT to OUTPUT_STACK OUTPUT_STACK=$OUTPUT_STACK$OUTPUT # add the NEW_SEP OUTPUT_STACK=$OUTPUT_STACK$NEW_SEP echo OUTPUT_STACK=$OUTPUT_STACK done echo echo # remove the last NEW_SEP OUTPUT_STACK=${OUTPUT_STACK%$NEW_SEP*} FINAL_OUPUT=$OUTPUT_STACK echo FINAL_OUPUT=$OUTPUT_STACK ;; ?-) echo "FIELDS is an open range" ;; ?) [[ $DEBUG ]] && echo "FIELDS is a single value" FIELD=$FIELDS get_one_field ;; esac