#!/bin/bash parssh () { (( $# )) || { _parssh_usage return $? } local origopts=$- set -m local _parssh_prepend_host=true while [[ "$1" == -* ]]; do case ${1#-} in [0-9]*) [[ "${1#-}" != *[^0-9]* ]] && { local _parssh_concurrency=${1#-} } ;; s|-servers) [[ -r "$2" ]] || { echo "'$2': invalid file name or permissions issue" return 99 } local _parssh_servers="$2" shift ;; r|-rinput) [[ -r "$2" ]] || { echo "'$2': invalid file name or permissions issue" return 98 } local _parssh_rinput="$2" shift ;; b|-bare) unset _parssh_prepend_host ;; h|-help) _parssh_usage return $? ;; esac shift done [[ -z "$_parssh_servers" ]] && { exec 9<&0 } || { exec 9<"$_parssh_servers" } while read host; do while (( $(jobs -pr | wc -l) >= ${_parssh_concurrency:-4} )); do sleep 1 done if [[ -z "$_parssh_rinput" ]]; then ssh -no StrictHostKeyChecking=no $host "$@" |\ _parssh_host_prepend & else ssh -To StrictHostKeyChecking=no $host "$@" < "$_parssh_rinput" |\ _parssh_host_prepend & fi done <&9 wait exec 9>&- [[ "${origopts//[^m]/}" == "m" ]] || set +m } _parssh_host_prepend () while read -r; do printf "${_parssh_prepend_host+$host: }%s\n" "$REPLY" done _parssh_usage () { printf ' %s\n'\ "SYNOPSIS"\ "parssh [-NUM] [-r|--rinput FILE] [-s|--servers FILE] [-b|--bare] [COMMANDS] [< SERVERS]"\ ""\ "DESCRIPTION"\ " -NUM (default: 4)"\ " Number of concurrent ssh connections to maintain. E.g. '-40'."\ " -r FILE, --rinput FILE (default: unset/inactive)"\ " File to send as STDIN redirection on remote servers."\ " (Can be used as replacement for or in conjunction with COMMANDS)."\ " -s FILE, --servers FILE (default: unset/inactive)"\ " File to use as list of servers to run COMMANDS on."\ " (Cannot be used in conjunction with a server list on STDIN)."\ " -b, --bare (default: unset/inactive)"\ " Disable prepending of hostname to each output line returned by COMMANDS on SERVERS."\ " COMMANDS"\ " The list of commands to be executed remotely by SSH on each SERVER."\ " < SERVERS"\ " Unless '-s' flag is used, STDIN will be used as list of remote servers."\ " (Deliniated by whitespace)." return 1 }