3

I know there are posts already on how to use subprocess in python to run linux commands but I just cant get the syntax correct for this one. please help. This is the command I need to run...

/sbin/ifconfig eth1 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'

Ok this is what I have at the moment that gives a syntax error...

import subprocess
self.ip = subprocess.Popen([/sbin/ifconfig eth1 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}'])

Any help greatly appreciated.

whoopididoo
  • 411
  • 2
  • 10
  • 19
  • Running the [useless grep](http://www.iki.fi/era/unix/award.html#grep) in Python makes no sense at all. Python is superbly equipped to perform the field extraction natively. – tripleee Sep 22 '15 at 09:19
  • 2
    @tripleee you don't need the external process at all here. Call `get_ip_address('eth1')` from [How can i get the IP Address of eth0 in Python?](http://stackoverflow.com/q/24196932/4279) – jfs Sep 22 '15 at 10:07
  • 1
    related: [How do I use subprocess.Popen to connect multiple processes by pipes?](http://stackoverflow.com/q/295459/4279) – jfs Sep 22 '15 at 10:08

2 Answers2

1

This has been gone over many, many times before; but here is a simple pure Python replacement for the inefficient postprocessing.

from subprocess import Popen, PIPE
eth1 = subprocess.Popen(['/sbin/ifconfig', 'eth1'], stdout=PIPE)
out, err = eth1.communicate()
for line in out.split('\n'):
    line = line.lstrip()
    if line.startswith('inet addr:'):
        ip = line.split()[1][5:]
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • @whoopididoo: `ip = re.search(br'inet addr:(\S+)', subprocess.check_output(['ifconfig', 'eth1'])).group(1)` – jfs Sep 22 '15 at 14:58
0

Here's how to construct the pipe in Python (rather than reverting to Shell=True, which is more difficult to secure).

from subprocess import PIPE, Popen

# Do `which` to get correct paths
GREP_PATH = '/usr/bin/grep'
IFCONFIG_PATH = '/usr/bin/ifconfig'
AWK_PATH = '/usr/bin/awk'

awk2 = Popen([AWK_PATH, '{print $1}'], stdin=PIPE)
awk1 = Popen([AWK_PATH, '-F:', '{print $2}'], stdin=PIPE, stdout=awk2.stdin)
grep = Popen([GREP_PATH, 'inet addr'], stdin=PIPE, stdout=awk1.stdin)
ifconfig = Popen([IFCONFIG_PATH, 'eth1'], stdout=grep.stdin)

procs = [ifconfig, grep, awk1, awk2]

for proc in procs:
    print(proc)
    proc.wait()

It'd be better to do the string processing in Python using re. Do this to get the stdout of ifconfig.

from subprocess import check_output

stdout = check_output(['/usr/bin/ifconfig', 'eth1'])
print(stdout)
Peter Sutton
  • 1,145
  • 7
  • 20
  • You are lacking the significant `-F :` option on `awk1`. It causes Awk to split the input on colons, instead of whitespace. Of course, the whole pipeline could be simply `awk '/inet addr:/ { print substr($2, 6) }'` – tripleee Sep 22 '15 at 09:42
  • 1
    @tripleee I've added the -F: option. – Peter Sutton Sep 22 '15 at 13:36
  • you should close the pipes in the parent otherwise you may hang child processes. Or [start the last command first and pass its stdin pipe to stdout of the preceding command](http://stackoverflow.com/a/9164238/4279). – jfs Sep 22 '15 at 14:37
  • @PeterSutton: you should get the output from `awk2` (set stdout=PIPE, call communicate()). You still should close the pipes (call communicate() instead of wait(), to avoid relying on the garbage collection to free file descriptors in the parent). – jfs Sep 23 '15 at 13:03