How to run simple single command on multiple Linux servers?

Hi All,

How can i run a single command on multiple servers with or without giving credentials.

I have a file(servers.txt) which has got list of servers and i want to run a command

lsb_release -dr

on all these servers and get output of those servers against each server.

I tried below code but it didn't work

tmpdir=${TMPDIR:-/tmp}/pssh.$$
mkdir -p $tmpdir
count=0
while IFS= read -r userhost; do
    ssh -n -o BatchMode=yes ${userhost} 'lsb_release -dr' > ${tmpdir}/${userhost} 2>&1 &
    count=`expr $count + 1`
done < servers.txt
while [ $count -gt 0 ]; do
    wait $pids
    count=`expr $count - 1`
done
echo "Output is in $tmpdir"

output of $ lsb_release -dr

Description:    Red Hat Enterprise Linux Server release 6.4 (Santiago)
Release:        6.4


is there any single line command which can give me the output as below

gbahelkm72.trp.expre.rmr   Release:        6.4
rtsahelkm98.trp.expre.rmr   Release:        6.4

Hi,

Here is some code that you should be able to easily adapt, this was one of the subroutines used to collect data from over 600 servers prior to a DCM - just adapt and substitute your own bits.

for HOST in `cat ${CONFDIR}/svr-access.conf | grep -v '^#'`
do
        OUTFILE=details-${HOST}.csv
        echo "checking ${HOST}"
        MSG "checking ${HOST}"
        HOSTNAME=`ssh ${HOST} "uname -n"`
        OS=`ssh ${HOST} "uname"`
        # ssh_get_os_details ${HOST} ${OS}
	MSG "Found ${HOSTNAME} running ${OS}"
MSG "JOB STEP 2"
        if [ ${OS} = "AIX" ]
        then
MSG "JOB STEP 3"
                if [ `echo ${OSVER} | cut -c1` -ne 4 ]
                then
                        ssh_get_aix56_getdetails ${HOST} > ${DATADIR}/${OUTFILE}
                fi
	elif [ ${OS} = "SunOS" ]
	then
MSG "JOB STEP 4"
	${FUNCDIR}/ssh_solaris_getdetails ${HOST} > ${DATADIR}/${OUTFILE}
        fi
done

Regards

Gull04

---------- Post updated at 12:51 PM ---------- Previous update was at 12:35 PM ----------

Hi,

Just for some more information, here is one of the more simple routines that are called in the ssh calling script.

############################################################################################
#
# Get the Memory info.....
#
############################################################################################

get_mem()
{
GETMEM=`ssh ${SSHHOST} "/usr/sbin/prtconf 2>&1 | grep -v devinfo | grep 'Memory size' | /usr/xpg4/bin/awk '{ print $1 }'"`
MEM=`echo ${GETMEM} | awk '{ print $3 }'`
GBMEM=`echo ${MEM} /1024 | bc`
MSG "${SSHHOST} Memory Check Executed."
}

Regards

Gull04

Note the awk path in the above example is only valid for Solaris. Not Linux.

/usr/bin/awk should be okay for Linux. Note: this likely is a symlink to /usr/bin/gawk which is the GNU version of awk.

ls -l /usr/bin/awk 

will show you what is going on

What's wrong? Do you get an error message?
I have omitted some stuff where I don't see a sense, and have prepended a hostname.

tmpdir=${TMPDIR:-/tmp}/pssh.$$
mkdir -p $tmpdir
echo "Output is in $tmpdir"
while read userhost
do
    (
    printf "%-29s " "$userhost"
    ssh -nx -o BatchMode=yes "$userhost" 'lsb_release -sd'
    ) </dev/null >"$tmpdir/$userhost" 2>&1 &
done < servers.txt
# wait until all bg jobs are done
wait

It is giving me the same host files which are there in servers.txt

Yes, I have assumed they are hostnames from servers.txt.
You did not say where gbahelkm72.trp.expre.rmr and rtsahelkm98.trp.expre.rmr come from.?

These are from servers.txt file.. this file has got hostnames

I'm not at all sure that I understand what you're trying to do, but note that the each of the background subshells started by:

    (
    printf "%-29s " "$userhost"
    ssh -nx -o BatchMode=yes "$userhost" 'lsb_release -sd'
    ) </dev/null >"$tmpdir/$userhost" 2>&1 &

writes to a different file for each host. If you want all of the output in a single file and you want to trim off the first part of the lsb_release output you need something more like:

    (
    release=$(ssh -nx -o BatchMode=yes "$userhost" 'lsb_release -sd')
    printf "%-29s %s\n" "$userhost" "Rel${release##*Rel}"
    ) </dev/null >>"$tmpdir/alluserhosts" 2>&1 &

clearing the output file before you start your loop with:

>"$tmpdir/alluserhosts"

unless you want the output in that file to grow each time you invoke your script.

Since I don't have access to a system with lsb_release installed, the above is totally untested. But, in theory, it should come close to what you seem to want.

Hmm I think asynchronous background jobs MUST go to separate logs.
Otherwise they might overwrite each other, and the shared log file becomes a mess.

Note that in the code I suggested in post #8, the output to the single log file is produced by a single invocation of the printf utility that uses an append redirection operator ( >> ) instead of the overwrite redirection operator ( > ) that was in the original code. Although not required by the standards, I would expect the output of that invocation of printf to be produced by a single write() system call, which, when writing the amount of data shown in the examples to a regular file, should be an atomic operation. Using the append redirection should prevent the concurrent background processes from overwriting each other's output and the single printf instead of multiple echo s should keep the output from the various background processes from being intermixed.