dotHello
dotHello

Reputation: 51

'list index out of range' from subprocess stdout

Whetever I do, I get this error when trying to print anything from 'ip_macAddr' using an index. Type is 'list' so I don't get why. The only explanation I have is that there's some type of caracter coming from the stdout of that subprocess that's messing things up.

Also I tried converting to string with no different result.

At this point I have ne clue. Thanks for your help!

Code

#!/usr/bin/env python3.7
import sys
import subprocess
import os

IP_NETWORK = '192.168.254.10'
IP_DEVICE = '192.168.254.194'

proc = subprocess.Popen(['ping', IP_NETWORK], stdout=subprocess.PIPE)

while True:
    line = proc.stdout.readline()
    # print(line)

    if not line:
        break
    connected_ip = line.decode('utf-8').split()[3].replace(':','')

    proc2 = subprocess.Popen(['ip', 'neigh', 'show', 'to', connected_ip], stdout=subprocess.PIPE)
    ip_macAddr = proc2.stdout.readline().decode('utf-8').split()

    
    print(connected_ip)
    # print(type(ip_macAddr))
    print(ip_macAddr[0])

Error

IndexError: list index out of range

edit 1

The output of print(ip_macAddr) would be: ['192.168.254.10', 'dev', 'wlp61s0', 'lladdr', '88:88:a1:b2:c3:88', 'REACHABLE']

edit 2

print(type(ip_macAddr)) returns <class 'list'>

edit 3 Traceback

Traceback (most recent call last):
  File "./device-connected-to-network.py", line 34, in <module>
    print(ip_macAddr[0])
IndexError: list index out of range

This would happen using ANY index and I also tried using: print(ip_macAddr[0]) or ip_macAddr = proc2.stdout.split()[0]

Again; same result using ANY index # and print(type(ip_macAddr)) returns type 'list'.

Another exemple;

The output of print(ip_macAddr)is ['192.168.254.10', 'dev', 'wlp61s0', 'lladdr', '74:83:c2:d2:a4:12', 'REACHABLE'].

So, if I do (in another file) - using index #4:

a = ['192.168.254.10', 'dev', 'wlp61s0', 'lladdr', '11:22:a1:b2:c3:33', 'REACHABLE']

print(type(a))
print(a[4])

The output is:

<class 'list'>
11:22:a1:b2:c3:33

So works as expected in this context, but not within the actual program.

Upvotes: 0

Views: 1201

Answers (1)

tripleee
tripleee

Reputation: 189397

split()[3] will fail with an IndexError on any line which has less than four whitespace-separated fields.

A common fix is to simply skip lines with fewer fields.

Similarly, if ip produces an empty string, splitting it produces an empty list, which you can't get the first element of.

You can also simplify your code by passing in text=True, and use subprocess.run() where you don't particularly need Popen(). I have also removed unused imports.

#!/usr/bin/env python3.7
import subprocess

IP_NETWORK = '192.168.254.10'
IP_DEVICE = '192.168.254.194'

proc = subprocess.Popen(['ping', IP_NETWORK],
     stdout=subprocess.PIPE, text=True)

while True:
    line = proc.stdout.readline()
    # print(line)

    if not line:
        break
    fields = line.split()

    if len(fields) < 4:
        continue

    connected_ip = fields[3].replace(':','')

    proc2 = subprocess.run(
        ['ip', 'neigh', 'show', 'to', connected_ip],
        capture_output=True, text=True)
    result = proc2.stdout

    if not result:
        continue

    ip_macAddr = result[0]

    print(connected_ip)
    # print(type(ip_macAddr))
    print(ip_macAddr)

Even better, trap and report any exceptions.

try:
    proc2 = subprocess.run(
        ['ip', 'neigh', 'show', 'to', connected_ip],
        capture_output=True, text=True,
        check=True)  # important
    result = proc2.stdout
except CalledProcessError as exc:
    print('`ip\' for', connected_ip, 'failed:', exc)
    continue

Upvotes: 1

Related Questions