When I execute a python script with this:
tsharkCall = ["tshark", "-a", "duration:6", "-i", "2", "-w", "thsark.pcap"]
tsharkProc = subprocess.Popen(tsharkCall, bufsize=0, executable="C:\\Program Files\\Wireshark\\tshark.exe")
A pcap file with the expected contents duly appears in the same folder as the script.
A second procedure to create a text file from the pcap does not work:
tsharkCall = ["tshark", "-i", "-", "<", "tshark.pcap", ">", "tshark.txt", "-V"]
tsharkProc = subprocess.Popen(tsharkCall, bufsize=0, executable="C:\\Program Files\\Wireshark\\tshark.exe")
I see "Capturing on Standard input" in the cmd window, but no "x packets captured", and no tshark.txt file appears in the folder.
From a command prompt in the same location, this does the job I am hoping for from the script:
>"C:\Program Files\Wireshark\tshark.exe" -i - < "tshark.pcap" > "tshark.txt" -V
It seems odd that one call works and the other doesn't. Any ideas as to what I'm missing?
subprocess.Popen by default bypasses CMD.EXE / sh, therefore command line I/O redirections (<, >) will not work. You can get a similar effect like this:
tsharkCall = ["tshark", "-i", "-", "-V"]
tsharkIn = open("tshark.pcap", "rb")
tsharkOut = open("tshark.txt", "wb")
tsharkProc = subprocess.Popen(tsharkCall,
stdin=tsharkIn,
stdout=tsharkOut,
executable="C:\\Program Files\\Wireshark\\tshark.exe")
This also works
tsharkCall = ["C:\\Program Files\\Wireshark\\tshark.exe", "-P", "-V", "-x", "-r", "C:\\Data\\PCAP_TEST_FILES\\test.pcap"]
tsharkOut = open("tshark.txt", "wb")
tsharkProc = subprocess.call(tsharkCall, stdout=tsharkOut)
Related
I have a batch file, something like this
#echo off
echo Good Morning
set /P convert=Convert? ^(y^/n^):
echo Favourite Day?
echo Monday:1 Tuesday:2...
set /P day=Number:
echo %day%
echo %convert%
And when I try to open it with python and subprocess with
import subprocess
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out = popen.communicate(input=b'n\n1\n')[0]
I get
Echo is off
and when I try to go line by line with
for line in popen.stdout
the subprocess just freezes. Is it possible to imitate user input in a batch file with python?
I called the batch file you included test.bat.
When I run this completed form of your code (Windows 10, python 3.8.5) without changing anything (except the loop at the end)
import subprocess
cmd = 'test.bat'
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out = popen.communicate(input=b'n\n1\n')[0]
for line in out.decode('cp1252').splitlines():
print(f'LINE: {line}')
I get (mostly) expected output.
LINE: Good Morning
LINE: Convert? (y/n):Favourite Day?
LINE: Monday:1 Tuesday:2...
LINE: Number:1
LINE: n
The only difference is that I was reading out rather than popen.stdout
I am trying to configure Ansible in an automatic way with the following def:
def configure_ansible():
with open('/etc/hosts', 'r') as f:
valid_ips=[line.split(None, 1)[0] for line in f]
if os.path.isfile('/etc/ansible/hosts'):
open('/etc/ansible/hosts', 'w').close()
os.system('cp /etc/hosts /etc/ansible/hosts')
for valid_ip in valid_ips:
os.system("sudo sed -i '14 s/^#//g' /etc/ansible/ansible.cfg")
os.system("sudo sed -i '22 s/^#//g' /etc/ansible/ansible.cfg")
if valid_ip == "localhost":
os.system("su - ansible -c 'echo -e '\n\n\n' | ssh-keygen -t rsa'")
os.system("su - ansible -c 'ssh-copy-id ansible#"+valid_ip)
Looks like the problem is inside the quotes of the last "if". Any idea how I can solve it?
UPDATE
I have followed chepner's recommendation, but the last line is not working properly. If I am using the code as below, the ssh-copy-id is not performed correctly and the ssh keys are not exchanged. I would need to introduce also the password to fully automate this process. Any idea how I can accomplish this?
Here is what I have tried:
def create_user():
users=["dante", "ansible"]
with open('/etc/hosts', 'r') as f:
valid_ips=[line.split(None, 1)[0] for line in f]
for valid_ip in valid_ips:
for user in users:
subprocess.call(["sudo", "useradd", user])
passwd_users = subprocess.Popen(["sudo", "passwd", user], stdin = subprocess.PIPE)
passwd_users.communicate(input = "test123\ntest123")
sudoers = open("/etc/sudoers", 'a')
sudoers.write(user + " ALL=(ALL) NOPASSWD: ALL \n")
sudoers.close()
def configure_ansible():
with open('/etc/hosts', 'r') as f:
valid_ips=[line.split(None, 1)[0] for line in f]
if os.path.isfile('/etc/ansible/hosts'):
open('/etc/ansible/hosts', 'w').close()
os.system('cp /etc/hosts /etc/ansible/hosts')
config = "/etc/ansible/ansible.cfg"
for valid_ip in valid_ips:
subprocess.call(["sudo", "sed", "-i", "14 s/^#//g", config])
subprocess.call(["sudo", "sed", "-i", "22 s/^#//g", config])
if valid_ip == "localhost":
keygen = subprocess.Popen(["sudo", "-u", "ansible", "ssh-keygen", "-t", "rsa"], stdin = subprocess.PIPE)
keygen.communicate(input = "\n\n\n")
copy_keygen = subprocess.Popen(["sudo", "-u", "ansible", "ssh-copy-id", "-o StrictHostKeyChecking=no", valid_ip], stdin = subprocess.PIPE)
copy_keygen.stdin.write('test123\n')
You are missing the closing single quote in that call to os.system:
os.system("su - ansible -c 'ssh-copy-id ansible#"+valid_ip+"'")
However, shell doesn't allow you to nest single quotes; the previous call should look something like:
os.system("su - ansible -c 'echo -e \"\n\n\n\" | ssh-keygen -t rsa'")
Even better, prefer subprocess.call to os.system in all cases:
config = "/etc/ansible/ansible.cfg"
for valid_ip in valid_ips:
subprocess.call(["sudo", "sed", "-i", "14 s/^#//g", config])
subprocess.call(["sudo", "sed", "-i", "22 s/^#//g", config])
if valid_ip == "localhost":
p = subprocess.Popen(["sudo", "-u", "ansible", "ssh-keygen", "-t", "rsa"])
p.communicate("\n\n\n")
subprocesss.call(["sudo", "-u", "ansible", "ssh-copy-id", "ansible#" + valid_ip])
At the moment I am using two separate shell script to get the job done.
1) Listing the current directory and saving it as a .html file (first listing only the root directory followed by complete listing)
tree -L 1 -dH ./ >> /Volumes/BD/BD-V1.html && tree -H ./ >> /Volumes/BD/BD-V1.html
2) Using sed to remove unwanted lines (I'm on mac)
sed -i '' '/by Francesc Rocher/d' /Volumes/BD/BD-V1.html && sed -i '' '/by Steve Baker/d' /Volumes/BD/BD-V1.html && sed -i '' '/by Florian Sesser/d' /Volumes/BD/BD-V1.html
Now I want to combine them as a single script with user input for the file path. I was trying to do with python but no success
import subprocess
subprocess.call(["tree", "-d", "-L", "1"])
The above one can list the directory but I couldn't save the output (I have to do this inside of python), I tried something like this but didn't get work.
file = open('out.txt', 'w')
import subprocess
variation_string = subprocess.call(["tree", "-d", "-L", "1"])
file.write(variation_string)
file.close()
Also I'm not sure how to implement sed :(
edit: I'm a beginner
You can simply redirect the stdout to a file object:
from subprocess import check_call
with open("out.txt","w") as f:
check_call(["tree", "-d", "-L", "1"],stdout=f)
In your code you are basically trying to write the return code as that is what call returns to the file which would raise an error as write expects a string. If you wanted to store the output of running a command you would use check_output.
You can do this with the subprocess module. You can create another process that runs your command, and then communicate with it. This will give you the output.
import subprocess
file = open('out.txt', 'w')
...
command = "tree -d -L 1"
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
output = process.communicate()[0]
...
file.write(output)
file.close()
How can I execute a shell command, can be complicated like normal command in bash command line, get the output of that command and pwd after execution?
I used function like this:
import subprocess as sub
def execv(command, path):
p = sub.Popen(['/bin/bash', '-c', command],
stdout=sub.PIPE, stderr=sub.STDOUT, cwd=path)
return p.stdout.read()[:-1]
And I check if user use cd command but that will not work when user use symlink to cd or other wierd way to change directory.
and I need a dictionary that hold {'cwd': '<NEW PATH>', 'result': '<COMMAND OUTPUT>'}
If you use subprocess.Popen, you should get a pipe object that you can communicate() for the command output and use .pid() to get the process id. I'd be really surprised if you can't find a method to get the current working directory of a process by pid...
e.g.: http://www.cyberciti.biz/tips/linux-report-current-working-directory-of-process.html
I redirect stdout to stderr of pwd command. if stdout is empty and stderr is not a path then stderr is error of the command
import subprocess as sub
def execv(command, path):
command = 'cd %s && %s && pwd 1>&2' % (path, command)
proc = sub.Popen(['/bin/bash', '-c', command],
stdout=sub.PIPE, stderr=sub.PIPE)
stderr = proc.stderr.read()[:-1]
stdout = proc.stdout.read()[:-1]
if stdout == '' and not os.path.exists(stderr):
raise Exception(stderr)
return {
"cwd": stderr,
"stdout": stdout
}
UPDATE: here is better implemention (using last line for pwd and don't use stderr)
def execv(command, path):
command = 'cd %s && %s 2>&1;pwd' % (path, command)
proc = sub.Popen(['/bin/bash', '-c', command],
env={'TERM':'linux'},
stdout=sub.PIPE)
stdout = proc.stdout.read()
if len(stdout) > 1 and stdout[-1] == '\n':
stdout = stdout[:-1]
lines = stdout.split('\n')
cwd = lines[-1]
stdout = '\n'.join(lines[:-1])
return {
"cwd": cwd,
"stdout": man_to_ansi(stdout)
}
To get output of an arbitrary shell command with its final cwd (assuming there is no newline in the cwd):
from subprocess import check_output
def command_output_and_cwd(command, path):
lines = check_output(command + "; pwd", shell=True, cwd=path).splitlines()
return dict(cwd=lines[-1], stdout=b"\n".join(lines[:-1]))
What I'd like to achieve is the launch of the following shell command:
mysql -h hostAddress -u userName -p userPassword
databaseName < fileName
From within a python 2.4 script with something not unlike:
cmd = ["mysql", "-h", ip, "-u", mysqlUser, dbName, "<", file]
subprocess.call(cmd)
This pukes due to the use of the redirect symbol (I believe) - mysql doesn't receive the input file.
I've also tried:
subprocess.call(cmd, stdin=subprocess.PIPE)
no go there ether
Can someone specify the syntax to make a shell call such that I can feed in a file redirection ?
Thanks in advance.
You have to feed the file into mysql stdin by yourself. This should do it.
import subprocess
...
filename = ...
cmd = ["mysql", "-h", ip, "-u", mysqlUser, dbName]
f = open(filename)
subprocess.call(cmd, stdin=f)
The symbol < has this meaning (i. e. reading a file to stdin) only in shell. In Python you should use either of the following:
1) Read file contents in your process and push it to stdin of the child process:
fd = open(filename, 'rb')
try:
subprocess.call(cmd, stdin=fd)
finally:
fd.close()
2) Read file contents via shell (as you mentioned), but redirect stdin of your process accordingly:
# In file myprocess.py
subprocess.call(cmd, stdin=subprocess.PIPE)
# In shell command line
$ python myprocess.py < filename
As Andrey correctly noticed, the < redirection operator is interpreted by shell. Hence another possible solution:
import os
os.system("mysql -h " + ip + " -u " + mysqlUser + " " + dbName)
It works because os.system passes its argument to the shell.
Note that I assumed that all used variables come from a trusted source, otherwise you need to validate them in order to prevent arbitrary code execution. Also those variables should not contain whitespace (default IFS value) or shell special characters.