Tags

, , ,

Solaris, while a fairly decent OS, can be a bit of a pain if you try and write some cross-Unix compatible scripts.

One of the functions I tend to use quite a bit is ‘seq’, a sequence generator:

~$ seq 1 10
1
2
3
4
5
6
7
8
9
10
~$

I use it in a couple of my scripts where I need to chunk, or ‘split’ some files without ending with cruft:

~$ cat /tmp/mylongfile| sed "$( seq -f 'n;' 2 5| tr -d '\n' )G;"
line 1
line 2
line 3
line 4
line 5

line 6
line 7
line 8
line 9
line 10

line 11
~$

All fair and well, but, as mentioned at the top of this post; Solaris is sometimes a bit of a pain. In this case, in particular, since Solaris is sans-‘seq’.

This is my version of ‘seq.sh’ for Solaris, especially when you don’t feel the need of dragging your C compiler closer and re-implementing it in binary; or you feel that using Perl or Python is simply overdoing matters:

#!/usr/bin/env ksh

seq() {
    __seq_PARM="";

    if [ "$1" = "-f" -o "${1##-f}" != "$1" ]; then
        if [ "$1" = "-f" ]; then
            __seq_PARM=$2;
            shift;
        else
            __seq_PARM="${1##-f}";
        fi
        shift;
    fi

    typeset -i __seq_START;
    typeset -i __seq_END;

    if [ $# -eq 1 ]; then
        __seq_START=0;
        __seq_END=$1;
    elif [ $# -eq 2 ]; then
        __seq_START=$1;
        __seq_END=$2;
    else
        echo "seq [-f format] [first] last" >&2;
        return;
    fi

    [ "${__seq_PARM}" = "" ] && __seq_PARM="%d";

    for (( __seq_i=${__seq_START}; __seq_i<=${__seq_END}; __seq_i++ )); do
        printf "${__seq_PARM}\n" $__seq_i;
    done
    unset __seq_PARM __seq_START __seq_END __seq_i;
}

__seq_CURR=$( echo $_| sed 's/.*\*//' );
if [[ $__seq_CURR = $0 ]]; then
    if [ "$1" = "-?" -o "$1" = "-h" -o "$1" = "--help" -o $# -eq 0 ]; then
        __seq_HELP="[-f format] [first] last"
        __seq_SNAME=$(basename $0);
        __seq_HELPTXT="${__seq_SNAME} usage:\n\nRun ${__seq_SNAME} directly:\n    $0 [-h|--help] ${__seq_HELP}\n\n";
        __seq_HELPTXT=${__seq_HELPTXT}"Source ${__seq_SNAME}:\n    . $0;\n    seq ${__seq_HELP}\n\n";

        printf "${__seq_HELPTXT}" >&2;
        unset __seq_HELPTXT __seq_HELP __seq_SNAME;
    else
        seq $@;
    fi
fi
unset __seq_CURR;

One of the (kinda) cool things this does is check whether you’re sourcing the file (inside your own script so you can run the seq function from there afterwards) or whether you’re running it directly (from the command-line, for example). Running it with a ‘-h‘ will attempt to explain… :-)

~$ /usr/local/bin/seq.sh -h
seq.sh usage:

Run seq.sh directly:
    /usr/local/bin/seq.sh [-h|--help] [-f format] [first] last

Source seq.sh:
    . /usr/local/bin/seq.sh;
    seq [-f format] [first] last

~$

As always, do with this as you will: you break it, you get to keep both pieces.

Update: 2015-10-15

A mere couple of hours after publishing the previous I realised that Solaris’ KSH (88) does not support for (( )) constructs. Of course not.

This means I had to replace the for (( )) loop with a while [[ ]] loop:

__seq_i=${__seq_START}
while [[ ${__seq_i} -le ${__seq_END} ]]; do
     printf "${__seq_PARM}\n" "${__seq_i}";
     let __seq_i=${__seq_i}+1
done

This should run nearly as fast as the previous loop, but will run on KSH-88, KSH-93 and Bash as well.

The updated seq.sh script now looks like this:

#!/usr/bin/env ksh

seq()
{
    __seq_PARM="";

    if [ "$1" = "-f" -o "${1##-f}" != "$1" ]; then
        if [ "$1" = "-f" ]; then
            __seq_PARM=$2;
            shift;
        else
            __seq_PARM="${1##-f}";
        fi
        shift;
    fi

    typeset -i __seq_START;
    typeset -i __seq_END;

    if [ $# -eq 1 ]; then
        __seq_START=0;
        __seq_END=$1;
    elif [ $# -eq 2 ]; then
        __seq_START=$1;
        __seq_END=$2;
    else
        echo "seq [-f format] [first] last" >&2;
        return;
    fi

    [ "${__seq_PARM}" = "" ] && __seq_PARM="%d";

    __seq_i=${__seq_START}
    while [[ ${__seq_i} -le ${__seq_END} ]]; do
        printf "${__seq_PARM}\n" "${__seq_i}";
        let __seq_i=${__seq_i}+1
    done
    unset __seq_PARM __seq_START __seq_END __seq_i;

}

__seq_CURR=$( echo $_| sed 's/.*\*//' );
if [[ $__seq_CURR = $0 ]]; then
    if [ "$1" = "-?" -o "$1" = "-h" -o "$1" = "--help" -o $# -eq 0 ]; then
        __seq_HELP="[-f format] [first] last"
        __seq_SNAME=$(basename $0);
        __seq_HELPTXT="${__seq_SNAME} usage:\n\nRun ${__seq_SNAME} directly:\n    $0 [-h|--help] ${__seq_HELP}\n\n";
        __seq_HELPTXT=${__seq_HELPTXT}"Source ${__seq_SNAME}:\n    . $0;\n    seq ${__seq_HELP}\n\n";

        printf "${__seq_HELPTXT}" >&2;
        unset __seq_HELPTXT __seq_HELP __seq_SNAME;
    else
        seq $@;
    fi
fi
unset __seq_CURR;