1

I am trying to use os.popen() to execute these 4 commands in Python over SSH.

The problem is coming up with the awk command , especially with its quotes.

Here is what I have to convert:

ssh -o BatchMode=yes -o StrictHostKeyChecking=no $host 'echo "<td>" $(uname -ri) "</td>"; free | grep "Mem:" | awk '\''{ print "<td>" $2/1024 " MB (" int($4*100/$2) "%) </td>" }'\''; free | grep "Swap:" | awk '\''{ print "<td>" int($3*100/$2) "%" }'\''; echo "</td><td>" $(cat /proc/cpuinfo | grep "processor" | wc -l) "@" $(cat /proc/cpuinfo | grep "MHz" | sort -u | awk '\''{ print $4 }'\'') "Mhz" $(cat /proc/cpuinfo | grep "cache size" | sort -u | awk '\''{ print "(" $4 " " $5 ")</td>" }'\'')' 

Here is what I have tried, but it comes up with some quotes errors in the last command. The problem seems to be with awk quotes. Also, I want to merge them into a single SSH instance.

os.popen("ssh 127.0.0.1 'echo \"<td>\" $(uname -ri) \"</td>\"'").read()

os.popen("ssh 127.0.0.1 free | grep \"Mem:\" | awk '{print \"<td>\" $2/1024 \" MB(\"int($4*100/$2)\"%)</td>\"}'").read()

os.popen("ssh 127.0.0.1 free | grep \"Swap:\" | awk '{ print \"<td>\" int($3*100/$2) \"%\" }'").read()

os.popen("ssh 127.0.0.1 'echo \"</td><td>\" $(cat /proc/cpuinfo | grep \"processor\" | wc -l) \"@\" $(cat /proc/cpuinfo | grep \"MHz\" | sort -u | awk '{ print $4 }') \"Mhz\" $(cat /proc/cpuinfo | grep \"cache size\" | sort -u | awk '{ print \"(\" $4 \" \" $5 \")</td>\" }')'").read()

Please help. A working set of commands would be appreciated.

Thanks

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
user2359303
  • 261
  • 2
  • 7
  • 15

3 Answers3

0

Sorry I don't have a target I can test to but you will find it a lot easier if you construct your string in triple quotes rather than single - this will cut the escaping needed and help you find your problem. I would also consider construct the string using "".join([ ]) again for readability.

Steve Barnes
  • 27,618
  • 6
  • 63
  • 73
  • I tried this os.popen(''' ssh 127.0.0.1 'echo "" $(uname -ri) "";free | grep "Mem:" | awk '{print "" $2/1024 " MB("int($4*100/$2)"%)"}' ' ''').read() – user2359303 Jun 25 '13 at 06:39
0

I thing you use for ssh python module(likes paramiko,pexpect...) my suggestion is pexpect use for example code Python: How can remote from my local pc to remoteA to remoteb to remote c using Paramiko , Python - Pxssh - Getting an password refused error when trying to login to a remote server

Community
  • 1
  • 1
Reegan Miranda
  • 2,879
  • 6
  • 43
  • 55
0

Besides that you should use subprocess rather than os.popen, in the context of shell commands quoting can easily done with

def shellquote(*strs):
    r"""Input: strings, output: String enclosed with '' and every ' replaced with '\''. For use with the shell."""
    # just take everything except '; replace ' with '\''
    # ''' is seen by the shell as ''\'''\'''\'''. Ugly, but not harmful.
    return " ".join([
            "'"+st.replace("'","'\\''")+"'"
            for st in strs
    ])

You can use it easily for compensating the shell's actions on the other side of the SSH connection.

import subprocess

def sshcall(*args):
    return subprocess.check_output(['ssh', '127.0.0.1'] + list(args))


sshcall('echo', sq("<td>") + '$(uname -ri)' + sq("</td>"))
# '<td>3.9.3-9.g0b5d8f5-desktop i386</td>\n'

sshcall('free | grep "Mem:" | awk ' + sq('{print "<td>" $2/1024 " MB(" int($4*100/$2) "%)</td>" }'))
# '<td>3017.93 MB(20%)</td>\n'

sshcall('free | grep "Swap:" | awk ' + sq('{ print "<td>" int($3*100/$2) "%" }'))
# '<td>3%\n'

The last line I'll leave as your example.


You can simplify this a lot by just asking the remote system for the data and transferring it yourself. In this case, you won't have to worry about shell quoting, because you do the most part of transformations on the local side. The connection is just used for querying raw information:

un = sshcall('uname -ri')
fr = sshcall('free')
cpu = sshcall('cat /proc/cpuinfo')

or even - for using only one connection -

un, fr, cpu = sshcall('uname -ri; echo XXXXX; free; echo XXXXX; cat /proc/cpuinfo').split("XXXXX")

You can analyze and output the data with

import re

do_re1 = lambda r, s: re.search(r, s).group(1).strip()
nums = lambda r, s: [int(x) for x in do_re1(r, s).split()]

print "<td>" + un.strip() + "</td>"

swapnums = nums("Swap:(.*)\n", fr)
memnums = nums("Mem:(.*)\n", fr)

print "<td> %f MB (%f %%) </td>" + % (memnums[0] / 1024.0, memnums[2] * 100.0 / memnums[0])
# swapnums: similiar

numcpus = len(re.findall("rocessor.*:(.*)\n", cpu))
freqs = [i.group(1).strip() for i in re.finditer("MHz.*:(.*)\n", cpu)]
cachesizes = [i.group(1).strip() for i in re.finditer("cache size.*:(.*)\n", cpu)]

# output them as you want
glglgl
  • 89,107
  • 13
  • 149
  • 217