-1

I have a python script that calculates Memory Used on a mac. It runs fine via terminal: ie. $>python freeMem.py | grep 'Memory Used' | awk '{print $5 }' 14264

**

  • freeMem.py:

**

# Get process info
ps = subprocess.Popen(['ps', '-caxm', '-orss,comm'], stdout=subprocess.PIPE).communicate()[0].decode()
vm = subprocess.Popen(['vm_stat'], stdout=subprocess.PIPE).communicate()[0].decode()

# Iterate processes
processLines = ps.split('\n')
sep = re.compile('[\s]+')
rssTotal = 0 # kB
for row in range(1,len(processLines)):
    rowText = processLines[row].strip()
    rowElements = sep.split(rowText)
    try:
        rss = float(rowElements[0]) * 1024
    except:
        rss = 0 # ignore...
    rssTotal += rss

# Process vm_stat
vmLines = vm.split('\n')
sep = re.compile(':[\s]+')
vmStats = {}
for row in range(1,len(vmLines)-2):
    rowText = vmLines[row].strip()
    rowElements = sep.split(rowText)
    vmStats[(rowElements[0])] = int(rowElements[1].strip('\.')) * 4096


#App_Memory =  sysctl vm.page_pageable_internal_count - Pages Purgable (from vm_stat)
cmd = "sysctl vm.page_pageable_internal_count"
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
(out, rc) = proc.communicate()
vmpage_pageable_internal_count = out.strip().decode('ascii').split(': ')[1]
vmpage_pageable_internal_count = int(vmpage_pageable_internal_count) * 4096
#print("Purgable internal count %d" % (vmpage_pageable_internal_count))

AppMemory = (vmpage_pageable_internal_count - vmStats["Pages purgeable"])/1024/1024
WiredMemory = vmStats["Pages wired down"]/1024/1024
ActiveMemory = vmStats["Pages active"]/1024/1024
InactiveMemory = vmStats["Pages inactive"]/1024/1024
CompressedMemory = vmStats["Pages occupied by compressor"] /1024/1024
UsedMemory = AppMemory + WiredMemory + CompressedMemory

print('Memory Used: %.3f GB %d MB' % (float(UsedMemory/1024), float(UsedMemory/1024 * 1000)))

However, when i tried to call it via any shell scripts, i.e: do shell script in applescript or os.system or subproces.Popen, run, call, etc... or even via back tick `` command in bash, it will return exactly the first two digits only with the rest being zeroes?: ie.: ./doGetMemUsed.sh 14000

content of doGetMemUsed.sh:

out=$(python freeMem.py | grep 'Memory Used' | awk '{print $5 }')
echo $out

Noticed last 3 digits are all gone and converted or rounded up to 0s?

I needed to get the last 3 digits as well, as these represents MB used, to be correctly calculated. Rounding it to GB is not accurate enough for my application.

I've tried using 10# to specify decimal in my bash script to no avail. I've tried casting it as integer in my python script, still no luck.

Only way i can get it to work is call it directly in terminal. But, i can't automate this via any scripting mechanism, because it would rely on shell underneath.

Any suggestions?

joseph
  • 9
  • 3
  • 1
    Please supply the expected [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) (MRE). We should be able to copy and paste a contiguous block of your code, execute that file, and reproduce your problem along with tracing output for the problem points. This lets us test our suggestions against your test data and desired output. Show where the intermediate results differ from what you expected. – Prune Mar 31 '21 at 17:50
  • You could improve formatting to help us distinguish _commands_ from _output_. Please post your python script as [example], otherwise it's hard to reproduce – hc_dev Mar 31 '21 at 17:51

1 Answers1

0

If you are doing any arithmetic in your shell script, be aware that most shells (ksh being an exception) cannot do floating point math. You might be doing something like:

$ x=14264789
$ echo $((x / 10**6 * 10**3))
14000

Fill in some more details in your question.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • I even tried to cast my calculation in python script to int and print out only the integer value. From command line test of the python script directly, it works. But, when i wrap it in bash shell script, it reverted back to the same issue. Please see output:cat doGetMemUsed.sh #!/bin/bash # script for tesing result=`python freeMem.py` echo $result $ ./doGetMemUsed.sh 13000 $ python freeMem.py 13401 $ python freeMem.py 13386 – joseph Mar 31 '21 at 18:17
  • The output is meaningless. Show the code in your question. – glenn jackman Mar 31 '21 at 20:06
  • the code is longer than i can attach, but here are the last part of it:cmd = "sysctl vm.page_pageable_internal_count" proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) (out, rc) = proc.communicate() vmpage_pageable_internal_count = out.strip().decode('ascii').split(': ')[1] vmpage_pageable_internal_count = int(vmpage_pageable_internal_count) * 4096 AppMemory = (vmpage_pageable_internal_count - vmStats["Pages purgeable"])/1024/1024 WiredMemory = vmStats["Pages wired down"]/1024/1024 CompressedMemory = vmStats["Pages occupied by compressor"] /1024/1024 – joseph Mar 31 '21 at 20:23
  • last 2 lines, due to limitations:UsedMemory = AppMemory + WiredMemory + CompressedMemory CalculatedMemoryUsed = int(UsedMemory/1024 * 1000) – joseph Mar 31 '21 at 20:27
  • So you don't do any of the arithmetic in bash, right? – glenn jackman Mar 31 '21 at 22:02
  • Nope. All the calculations are done in Python and the python script works on terminal as I said above. The only issue is when we try to call it from Shell, shellscript, subprocess, ``, os.system, etc.... Something is not right. If it works in terminal, it should work the same way if we call it from shell script or bash shell. Blows my mine... i've spent over a week on this issue to no avail. Seems no one has a clear answer for this. This is run on Mac OS Catalina, latest. – joseph Apr 01 '21 at 22:23