Getting error while executing ping through subprocess.call() - python

I have given
subprocess.call(['ping', '127.0.0.1', '>>', 'out15.txt'])
statement in python script.
But I am getting unknown host error.
Please let me know why I am getting that error.

Cause you pass the >> out15.txt to the ping as argument.
The >> is special character of cmd\bash. If you insist to redirect the output to file with the command, instead using python code you can do that like this:
subprocess.call(['cmd', '/c', 'ping', '127.0.0.1', '>>', 'out15.txt'])
The same for bash.

As #Ori Seri pointed out >> is usually interpreted by a shell:
from subprocess import call
call('ping 127.0.0.1 >> out15.txt', shell=True)
Note: the string argument with shell=True.
You could do it without the shell:
with open('out15.txt', 'ab', 0) as output_file:
call(["ping", "127.0.0.1"], stdout=output_file)
Note: the list argument with shell=False (the default).
You don't need to write the output file to interpret the ping results; you could use the exit status instead:
from subprocess import call, DEVNULL
ip = "127.0.0.1"
rc = call(["ping", '-c', '3', ip], stdout=DEVNULL)
if rc == 0:
print('%s active' % ip)
elif rc == 2:
print('%s no response' % ip)
else:
print('%s error' % ip)
See Multiple ping script in Python.

Related

subprocess.CalledProcessError: returned non-zero exit status 1 for non-pingable destination

I am writing a python script to calculate packet loss through ping an IP address using subprocess module in linux. More than one IP address kept in CSV file. It is running fine when the pingable destination are only given.
But throwing an error when the non-pingable IP given in the CSV file and then the script is exiting without checking the other IP address in that CSV file. So I am not able to capture the packet loss for the non-pingable destination which is the main purpose the script.
Please suggest a way forward.
subprocess.check_output(['ping','-c 4',hostname], shell=False,
universal_newlines=True).splitlines()
subprocess.CalledProcessError: Command '['ping', '-c 4', '192.168.134.100']' returned non-zero exit status 1
It is just that subprocess returns an error if your ping has 100% packet loss, destination unreachable or any other problem. What you could do is:
try:
# subprocess code here
except:
# some code here if the destination is not pingable, e.g. print("Destination unreachable..") or something else
pass # You need pass so the script will continue on even after the error
Try this Code:
import subprocess
def systemCommand(Command):
Output = ""
Error = ""
try:
Output = subprocess.check_output(Command,stderr = subprocess.STDOUT,shell='True')
except subprocess.CalledProcessError as e:
#Invalid command raises this exception
Error = e.output
if Output:
Stdout = Output.split("\n")
else:
Stdout = []
if Error:
Stderr = Error.split("\n")
else:
Stderr = []
return (Stdout,Stderr)
#in main
Host = "ip to ping"
NoOfPackets = 2
Timeout = 5000 #in milliseconds
#Command for windows
Command = 'ping -n {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
#Command for linux
#Command = 'ping -c {0} -w {1} {2}'.format(NoOfPackets,Timeout,Host)
Stdout,Stderr = systemCommand(Command)
if Stdout:
print("Host [{}] is reachable.".format(Host))
else:
print("Host [{}] is unreachable.".format(Host))

Sending two commands over ssh in one subprocess.Popen list

#!/usr/bin/python
import subprocess
import sys
HOST=raw_input("\nInsert server(ex: xxXX.city):\n\n")
IP=raw_input("\nInsert ip:\n\n")
print ''
COMMAND='show arp hostname %s' % IP
COMMAND2='show route table inet.0 %s' % IP
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND, COMMAND2],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == 'xxx':
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print ''.join(result)
I get this error:
error: syntax error: show
I'm guessing there is a problem with two commands chained in a subprocess.Popen. I say this because it looks like it executes each one with no problem. It's only when I put them chained that I get the error. I looked it up but I haven't found something clear about making two commands in one go with Popen..is there a way to make them work like the above but with a little twist or do I have to change the subprocess? thank you
with help from a friend the problem got solved like this:
ssh = subprocess.Popen(["ssh", "%s" % HOST, ';'.join([COMMAND, COMMAND2])],

Running commands on remote server and saving the result to a string variable in a Python script [duplicate]

This question already has answers here:
Python how to read output from pexpect child?
(8 answers)
Closed 6 years ago.
How can I run commands on the remote server to which I login to, using pexpect and store the result in the form of a string into a variable?
I made a connection to the server in the following way:
COMMAND_PROMPT = '[#$] '
TERMINAL_PROMPT = '(?i)terminal type\?'
TERMINAL_TYPE = 'vt100'
SSH_NEWKEY = '(?i)are you sure you want to continue connecting'
child = pexpect.spawn('ssh -l %s %s'%(loginuser, servername))
i = child.expect([pexpect.TIMEOUT, SSH_NEWKEY, COMMAND_PROMPT, '(?i)password'])
if i == 0: # Timeout
print('ERROR! could not login with SSH. Here is what SSH said:')
print(child.before, child.after)
print(str(child))
sys.exit (1)
if i == 1: # In this case SSH does not have the public key cached.
child.sendline ('yes')
child.expect ('(?i)password')
if i == 2:
# If a public key was setup to automatically login
pass
if i == 3:
child.sendline(password)
# Now we are either at the command prompt or
# the login process is asking for our terminal type.
i = child.expect ([COMMAND_PROMPT, TERMINAL_PROMPT])
if i == 1:
child.sendline (TERMINAL_TYPE)
child.expect (COMMAND_PROMPT)
Now suppose I want to execute the following command on the server I logged in to and save the result to a string in my python script itself:
ps -ef|grep process1
How can this be done?
I think this might help you.
import subprocess
import sys
url="http://www.anyurlulike.any"
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"
ssh = subprocess.Popen(["ssh", "%s" % url, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
You can use read() function, it will give you the entire output.
result = child.read()

Get output of system ping without printing to the console

I want to call ping from Python and get the output. I tried the following:
response = os.system("ping "+ "- c")
However, this prints to the console, which I don't want.
PING 10.10.0.100 (10.10.0.100) 56(86) bytes of data.
64 bytes from 10.10.0.100: icmp_seq=1 ttl=63 time=0.713 ms
64 bytes from 10.10.0.100: icmp_seq=2 ttl=63 time=1.15 ms
Is there a way to not print to the console and just get the result?
To get the output of a command, use subprocess.check_output. It raises an error if the command fails, so surround it in a try block.
import subprocess
try:
response = subprocess.check_output(
['ping', '-c', '3', '10.10.0.100'],
stderr=subprocess.STDOUT, # get all output
universal_newlines=True # return string not bytes
)
except subprocess.CalledProcessError:
response = None
To use ping to know whether an address is responding, use its return value, which is 0 for success. subprocess.check_call will raise and error if the return value is not 0. To suppress output, redirect stdout and stderr. With Python 3 you can use subprocess.DEVNULL rather than opening the null file in a block.
import os
import subprocess
with open(os.devnull, 'w') as DEVNULL:
try:
subprocess.check_call(
['ping', '-c', '3', '10.10.0.100'],
stdout=DEVNULL, # suppress output
stderr=DEVNULL
)
is_up = True
except subprocess.CalledProcessError:
is_up = False
In general, use subprocess calls, which, as the docs describe, are intended to replace os.system.
If you only need to check if the ping was successful, look at the status code; ping returns 2 for a failed ping, 0 for a success.
I'd use subprocess.Popen() (and not subprocess.check_call() as that raises an exception when ping reports the host is down, complicating handling). Redirect stdout to a pipe so you can read it from Python:
ipaddress = '198.252.206.140' # guess who
proc = subprocess.Popen(
['ping', '-c', '3', ipaddress],
stdout=subprocess.PIPE)
stdout, stderr = proc.communicate()
if proc.returncode == 0:
print('{} is UP'.format(ipaddress))
print('ping output:')
print(stdout.decode('ASCII'))
You can switch to subprocess.DEVNULL* if you want to ignore the output; use proc.wait() to wait for ping to exit; you can add -q to have ping do less work, as it'll produce less output with that switch:
proc = subprocess.Popen(
['ping', '-q', '-c', '3', ipaddress],
stdout=subprocess.DEVNULL)
proc.wait()
if proc.returncode == 0:
print('{} is UP'.format(ipaddress))
In both cases, proc.returncode can tell you more about why the ping failed, depending on your ping implementation. See man ping for details. On OS X the manpage states:
EXIT STATUS
The ping utility exits with one of the following values:
0 At least one response was heard from the specified host.
2 The transmission was successful but no responses were received.
any other value
An error occurred. These values are defined in <sysexits.h>.
and man sysexits lists further error codes.
The latter form (ignoring the output) can be simplified by using subprocess.call(), which combines the proc.wait() with a proc.returncode return:
status = subprocess.call(
['ping', '-q', '-c', '3', ipaddress],
stdout=subprocess.DEVNULL)
if status == 0:
print('{} is UP'.format(ipaddress))
* subprocess.DEVNULL is new in Python 3.3; use open(os.devnull, 'wb') in it's place in older Python versions, making use of the os.devnull value, e.g.:
status = subprocess.call(
['ping', '-q', '-c', '3', ipaddress],
stdout=open(os.devnull, 'wb'))

Reading from pipe in python is imposiible

Hello I have the following code in python 2.6:
command = "tcpflow -c -i any port 5559"
port_sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, shell=True)
while True:
line = port_sniffer.stdout.readline()
#do some stuff with line
The purpose of this code is to sniff the traffic between two processes (A and B) that communicate on port 5559.
Now let me describe the different scenarios I am having:
1) Code above is not running:
A and B are communicating and i can see it clearly using logs and the linux command netstat -napl | grep 5559 shows that the processes are communicating on the desired port.
2) Code above is not running and I am sniffing by running tcpflow -c -i any port 5559 directly from shell:
I can see the communication on console clearly :-).
3) Code above is running: Proccesses can't communicate. netstat -napl | grep 5559 prints nothing and logs give out errors!!!
4) Code above is running in debug mode: I can't seem to be able to step after the line line = port_sniffer.stdout.readline()
I tried using an iterator instead of a while loop (not that it should matter but still I am pointing it out). I also tried different values for bufsize (none, 1, and 8).
Please help!!
So after a quick read through the docs I found these two sentences:
On Unix, if args is a string, the string is interpreted as the name or
path of the program to execute
and
The shell argument (which defaults to False) specifies whether to use
the shell as the program to execute. If shell is True, it is
recommended to pass args as a string rather than as a sequence.
Based on this, I would recommend recreating your command as a list:
command = ["tcpflow -c", "-i any port 5559"] #I don't know linux, so double check this line!!
The general idea is this (also from the docs):
If args is a sequence, the first item specifies the command string,
and any additional items will be treated as additional arguments to
the shell itself. That is to say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
Additionally, it seems that to read from your process, you should use communicate(). So
while True:
line = port_sniffer.stdout.readline()
would become
while True:
line = port_sniffer.communicate()[0]
But keep in mind this note from the docs:
Note The data read is buffered in memory, so do not use this method if the data size is large or unlimited.
If I had to guess, I think the problem that you're having is that you aren't running your program as root. TCPFlow needs to be run as a privelaged user if you want to be able to sniff other people's traffic (otherwise that'd be a serious security vulnerability). I wrote the following programs and they worked just fine for your scenario
server.py
#!/usr/bin/python
import socket
s = socket.socket()
host = socket.gethostname()
port = 12345
s.bind((host,port))
s.listen(5)
while True:
c, addr = s.accept()
print 'Connection from', addr
c.send('Test string 1234')
c.recv(1024)
while x != 'q':
print "Received " + x
c.send('Blah')
x = c.recv(1024)
print "Closing connection"
c.close()
client.py
#!/usr/bin/python
import socket, sys
from time import sleep
from datetime import datetime
s = socket.socket()
host = socket.gethostname()
port = 12345
s.connect((host,port))
c = sys.stdin.read(1) # Type a char to send to initate the sending loop
while True:
s.send(str(datetime.now()))
s.sleep(3)
msg = s.recv(1024)
flow.py
#!/usr/bin/python
import subprocess
command = 'tcpflow -c -i any port 12345'
sniffer = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
while True:
print sniffer.stdout.readline()

Categories

Resources