0

I am trying to write my below pinging script results into a Text file, but i got an error message.

Below is my code:

import os
import time
import subprocess


# Open file for saving ping results
results_file = open("results.txt", "w")

with open('ip-source.txt') as IPs:
    hosts = IPs.read()
    hosts = hosts.splitlines()
    for ip in hosts:
        os.system('cls')
        print('Printing now:', ip)
        print('-'*60)
        result = os.system('ping -n 4 {}'.format(ip))
        print('-'*60)
        time.sleep(1)

with open("output.txt", "w", encoding="utf8") as output:
    output.write("\n".join([post.text for post in result]))

and when i ran it i got below error message:

Traceback (most recent call last):
File "script.py", line 21, in <module>
output.write("\n".join([post.text for post in result]))
TypeError: 'int' object is not iterable
Tsubasa
  • 1,389
  • 11
  • 21
Ahmed M.
  • 49
  • 1
  • 7

2 Answers2

1

os.system returns the exit signal (typically 0 or 1) from the process called. If you look, os.system is actually just a wrapper function for subprocess.Popen.

You'll want to a) use something like subprocess.Popen or subprocess.check_output and then b) add results to a list:

import subprocess
...
results = []
for ip in hosts:
    ...
    results.append(str(subprocess.check_output(["ping", "-n", "4", str(ip)])))

with open("output.txt", "w", encoding="utf8") as output:
    output.writelines(results)
M Z
  • 4,571
  • 2
  • 13
  • 27
  • Unfortunatuly i got below error: Traceback (most recent call last): File "script.py", line 23, in output.writelines(results) TypeError: write() argument must be str, not bytes – Ahmed M. Aug 25 '20 at 05:33
  • You can fix that with `text=True` but I'll post a separate answer with more details. – tripleee Aug 25 '20 at 05:35
  • 1
    @AhmedM. Just convert the output to a `str` object then – M Z Aug 25 '20 at 05:35
  • 1
    Lovely bro, it worked after converted the output to str! Thanks! – Ahmed M. Aug 25 '20 at 05:36
1

Probably better to open the output file once, then have each of the subprocesses append to it as you go.

with open('ip-source.txt') as IPs, open("output.txt", "w") as output:
    for ip in IPs:
        subprocess.run(
            ['ping', '-n', '4', ip.rstrip('\n')],
            stdout=output, text=True, check=True)

Notice also how this avoids invoking a shell at all.

You could streamline this slightly by opening the output file as binary; then you can take out the text=True and let the file accept raw bytes (even though they are eventually going to be parsed as Unicode strings by whatever reads the text file subsequently).

In Python 3, a subprocess returns bytes by default; you then have to decode those bytes into a str (once you know their encoding); or you can specify text=True to have Python transparently encode and decode all these bytes as strings, using the default encoding (UTF-8 on any adult system; YMMV on Windows).

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • How can exclude those ping results with ``Request timed out.`` or ``destination unreachable`` because it causes a problem later in analysis – Ahmed M. Aug 28 '20 at 07:11
  • Then you can't write directly to the file, or maybe you'll want to `grep -v -e 'Request timed out' -e 'destination unreachable' file` and take it from there. To filter them out while Python is reading, use `result = subprocess.run(..., capture=True)` and loop over `result.stdout.splitlines()` to filter out the ones you don't want. This isn't hard to find from the `subprocess` documentation; ask a new question if you can't figure it out. – tripleee Aug 28 '20 at 08:52