0

Essentially, I want to create a script with multiple choices to check certain data on a hostname. For example, the code here will have an option to ping or run a tracert on a given hostname.

import os

print("""What did you want to run? (pick a number)
        (1) Ping
        (2) Traceroute""")

runit = raw_input("> ")

print ("Enter a hostname to check")
host = raw_input("> ") #accept input for hostname

if runit == "1":
    os.system("cmd /c ping " + host) 
elif runit == "2":
    os.system("cmd /c tracert " + host)

The code above works and I can get the results and manually copy them, but I would like this to be done automatically. I know I can open files using something like

p = open("ping1.txt", "w")

But I am not sure how to copy the results of the trace or the ping from the command prompt? Any help would be appreciated.

Laurel
  • 5,965
  • 14
  • 31
  • 57
Matt
  • 79
  • 1
  • 8

3 Answers3

0

You can use subprocess.Popen to see the output and write to a file:

from subprocess import Popen, PIPE
print("""What did you want to run? (pick a number)
        (1) Ping
        (2) Traceroute""")

runit = raw_input("> ")

print ("Enter a hostname to check")
host = raw_input("> ") #accept input for hostname

if runit == "1":
    p  = Popen("cmd /c ping " + host, shell=True, stdout=PIPE)
    with open("ping.txt","w") as f:
        for line in iter(p.stdout.readline,""):
            print(line)
            f.write(line)

elif runit == "2":
     p = Popen("cmd /c tracert " + host, shell=True, stdout=PIPE)
     with open("trace.txt", "w") as f:
         for line in iter(p.stdout.readline, ""):
             print(line)
             f.write(line)

To keep the code dry and allow a user to choose again if they select the wrong choice, you can use a while loop with str.format with a dict to keep the options:

from subprocess import Popen, PIPE

opts = {"1": "ping", "2": "tracert"}

while True:
    print("""What did you want to run? (pick a number)
            (1) Ping
            (2) Traceroute""")
    runit = raw_input("> ")
    if runit in opts:
        host = raw_input("Enter a hostname to check\n> ")  # accept input for hostname
        p = Popen("cmd /c {} {}".format(opts[runit], host), shell=True, stdout=PIPE)
        with open("ping.txt", "w") as f:
            for line in iter(p.stdout.readline, ""):
                print(line)
                f.write(line)
        break
    print("Invalid option")
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • Yes, this works exactly as I was hoping. Thanks a lot! still a bit unfamiliar with subprocess arguments like shell=1, stdout=PIPE, but I found the page and will read more up on it. I understand the rest and appreciate it! – Matt May 17 '16 at 22:17
  • No worries, you can normally get away with passing a list of individual args without setting shell=True but I don't ever use windows so I am not too sure if it would or not as I know some commands need shell=True when using window – Padraic Cunningham May 17 '16 at 22:24
  • 1- you could use `stdout=file` instead 2- no need to repeat the code. Compare with [this](http://stackoverflow.com/a/37311520/4279) – jfs May 18 '16 at 23:14
  • @J.F.Sebastian, 1. I am aware of how to redirect the output to a file, the OP wanted both the output to the shell and saved to a file which this provides. 2. The edit takes care of that, I would recommend you use a try/except in your code when casting user input to int, also you might consider using a dict as per my ans, your code will also error if a number > 2 is entered so that is also something you might want to catch. – Padraic Cunningham May 19 '16 at 09:30
  • @PadraicCunningham: 1- could you point to a specific sentence in the question/comment where OP says that the output should be both to the file and stdout? 2- if you have comments about my answer; leave them under my answer (though, I don't think I need to pollute the answer to the [subprocess] question with unrelated to the question error handling of the user input. btw, I don't see where you follow your own recommendations (not that you should in this case). – jfs May 20 '16 at 08:57
  • @J.F.Sebastian, *Yes, this works exactly as I was hoping.*, that for me would be a good clue that I provided exactly how I interpreted the question considering it is from the person that asked it, as far as polluting the answers goes you may want to revisit your *2- no need to repeat the code*. – Padraic Cunningham May 20 '16 at 09:04
  • @Matt: do you need the output of the subprocess to a file *and* the console. Is it enough if the output goes only to the file? – jfs May 20 '16 at 09:07
0

os.system(command) executes the command in a subshell and returns its exit status on most system (at least for cmd.exe).

The subprocess module is much for suitable for doing anything more than that.

You probably want to use subprocess.check_output which runs the command with arguments and return its output as a byte string.

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)`
Simon Fromme
  • 3,104
  • 18
  • 30
  • Once you have the output as a byte string the rest should be trivial. Although 'subprocess.check_output()' is probably not suitable if the command is not guaranteed to terminate as with `ping` if you dont specify a `-c count`. Then the solution proposed by Padraic Cunningham is better! – Simon Fromme May 17 '16 at 22:25
-1

To redirect the output of a command to a file, you could pass stdout parameter to subprocess.check_call():

#!/usr/bin/env python2
import subprocess

one_or_two = raw_input("""What did you want to run? (pick a number)
        (1) Ping
        (2) Traceroute
> """)
command = ["", "ping", "tracert"][int(one_or_two)]
host = raw_input("Enter a hostname to check\n> ") 

with open('output.txt', 'wb', 0) as file:
    subprocess.check_call([command, host], stdout=file)

If you want to display the output in the console in addition to copying the output to a file, see Displaying subprocess output to stdout and redirecting it.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670