#!/bin/bash
pname=$(basename "$0")
verbose=1

HOSTS=(
    proteus.sbde.fr
    hubble.informatimago.com
    kuiper.lan.informatimago.com
    despina.lan.informatimago.com
    larissa.lan.informatimago.com
    # lassell.lan.informatimago.com
    # galatea.lan.informatimago.com
    # triton.lan.informatimago.com
    # galle.lan.informatimago.com
    # voyager.informatimago.com
)


function usage(){
    local space="${pname//./ }"
    printf "%s usage:\n" "$pname"
    printf "\n"
    printf "    %s [-s|-h|-v]  command arguments...\n" "$pname"
    printf "    %s [-s|-h|-v]  -f script\n" "$pname"
    printf "\n"
    printf "    %s -s          outputs only the output of command.\n" "$space"
    printf "    %s -h          prefix the output of command by the host name.\n" "$space"
    printf "    %s -v          prefix the output of command by the host name and command.\n" "$space"
    printf "    %s -f script   copies the script to the remote hosts and runs it there.\n" "$space"
    printf "\n"
}

function docmd(){
    if [ $verbose -ge 2 ] ; then
        printf "# %s\n" "$*"
    fi
    "$@"
}

function hostheader(){
    local h="$1"
    case "$verbose" in
    1)
        printf "### %-16s" "${h/\.*/}"
        ;;
    2)
        printf "### %-16s\n" "${h/\.*/}"
        ;;
    esac
}


function quote(){
    for arg ; do
        local slash=${arg//\\/\\\\}
        local quote=\'${slash//\'/\'\\\'\'}\' # no "${...}" here! It would break the \'
        printf "%s " ${quote}
    done
    printf "\n"
}


function all_hosts(){
    local args="$(quote "${@}")"

    # AHOSTS=
    # for h in $HOSTS ; do
    #     ping -q -c 1 -w 4 $h >/dev/null 2>&1 \
        #         && AHOSTS="$AHOSTS $h"
    # done

    local ahosts=(${HOSTS[@]})


    # printf "script='%s'\n" "$script"
    # printf "remtemp='%s'\n" "$remtemp"
    # printf "command='%s'\n" "${command[@]}"
    # printf "args=%s\n" "$args"
    # exit 0

    for h in ${ahosts[@]} ; do
        hostheader "$h"
        if [ -n "$script" ] ; then
            remtemp="${pname}-${script}-$(hostname)-${h}-$$.sh"
            if [ $verbose -gt 0 ] ; then
                verbose=2
            fi
            docmd scp "$script" "${h}:~/${remtemp}"
            docmd ssh -x "${h}" bash -c "\"( chmod 755 ~/${remtemp} ; ~/${remtemp} > ~/${remtemp}.out 2> ~/${remtemp}.err ; rm ~/${remtemp} )\""
            docmd scp "${h}:~/${remtemp}.out" "${h}:~/${remtemp}.err" /tmp/
            docmd ssh -x "${h}" bash -c "\"( rm ~/${remtemp}.out ~/${remtemp}.err )\""
            docmd cat /tmp/${remtemp}.out /tmp/${remtemp}.err
        else
            docmd ssh -x $h bash -c "$(quote "$args")"
        fi
    done
}

function main(){
    expect=none
    script=""
    command=()
    while [ $# -gt 0 ] ; do
        case $expect in
        (none)
            case "$1" in
            (-s|--short)
                verbose=0
                shift
                ;;
            (-h|--host)
                verbose=1
                shift
                ;;
            (-v|--verbose)
                verbose=2
                shift
                ;;
            (-f|--script)
                shift
                script="$1"
                shift
                ;;
            (--)
                expect=command
                shift
                ;;
            (-*)
                usage
                exit 1
                ;;
            (*)
                expect=command
                command[${#command[@]}]="$1"
                shift
                ;;
            esac
            ;;
        (command)
            command[${#command[@]}]="$1"
            shift
            ;;
        esac
    done

    if [ -n "$script" ] ; then
        if [ ${#command[@]} -gt 0 ] ; then
            printf "%s error: cannot give -f script and command arguments at the same time.\n" "$pname"
            usage
            exit 1
        fi
        if [ ! -r "$script" ] ; then
            printf "%s error: cannot read %s.\n" "$pname" "$script"
            usage
            exit 1
        fi
    fi

    all_hosts "${command[@]}"
}

main "$@"




#### END ####
ViewGit