Expected Behavior
Under normal circumstances, I can issue tshark -E separator='#' under linuxSee Note A and force it to display fields separated by #, as shown below...
[mpenning#hotcoffee ~]$ tshark -r scp_test.pcap -e frame.number -e ip.src_host -e tcp.srcport -E separator='#' -T fields tcp | less
1#192.168.12.236#33088
2#192.168.12.238#22
3#192.168.12.236#33088
...
Unexpected Behavior
Likewise, I thought I would run the same command through subprocess.Popen(), columnify, and colorize based on some analysis... all my analysis depends on the output being separated by # when I run the script... however, my script is not using #... instead, it uses a single-quote; I am not sure I understand why this is happening.
Script
import subprocess
import sys
filename = sys.argv[1].strip()
fields = ['frame_num', 'IP Src', 'TCP Src']
sep = '#'
cmd = r"""tshark -r %s -e frame.number -e ip.src_host -e tcp.srcport -E separator='%s' -T fields tcp""" % (filename, sep)
subcmd = cmd.split(' ')
lines = subprocess.Popen(subcmd, stdout = subprocess.PIPE)
for line in lines.communicate()[0].split('\n'):
print line
Results
[mpenning#hotcoffee ~]$ python analyze.py scp_test.pcap | less
1'192.168.12.236'33088
2'192.168.12.238'22
3'192.168.12.236'33088
4'192.168.12.238'22
5'192.168.12.236'33088
6'192.168.12.236'33088
7'192.168.12.238'22
8'192.168.12.236'33088
It seemingly does not matter whether I assign sep using any of the following...
sep = '#'
sep = '\#'
sep = re.escape('#') # Desperation attempt ;-)
Question
Can someone explain:
Why my output is not separated with # in the script above.
How I can fix the script using subprocessSee Note B?
End-Notes
Note A. System information:
[mpenning#hotcoffee ~]$ python -V
Python 2.6.6
[mpenning#hotcoffee ~]$ uname -a
Linux hotcoffee 2.6.32-5-amd64 #1 SMP Mon Mar 7 21:35:22 UTC 2011 x86_64 GNU/Linux
[mpenning#hotcoffee ~]$
Note B. Answers using os.system() or os.popen() are not what I'm looking for
tshark is taking the ' from '%s'. don't use the single-quotes:
cmd = r"tshark -r %s -e frame.number -e ip.src_host -e tcp.srcport -E separator=%s -T fields tcp" % (filename, sep)
when you ran it from the command line, Bash stripped the single-quotes off and tshark didn't see them.
Related
I made a python3 script and i need to run a bash command to make it work. i have tried os.system and subprocess but neither of them fully work to run the whole command, but when i run the command by itself in the terminal then it works perfect. what am i doing wrong?
os.system("fswebcam -r 640x480 --jpeg 85 -D 1 picture.jpg &> /dev/null")
os.system("echo -e "From: abc#gmail.com\nTo: abc1#gmail.com\nSubject: package for ryan\n\n"package for ryan|uuenview -a -bo picture.jpg|sendmail -t")
or
subprocess.run("fswebcam -r 640x480 --jpeg 85 -D 1 picture.jpg &> /dev/null")
subprocess.run("echo -e "From: abc#gmail.com\nTo: abc1#gmail.com\nSubject: package for ryan\n\n"package for ryan|uuenview -a -bo picture.jpg|sendmail -t")
This is supposed to take a picture and email it to me. With os.command it gives an error "the recipient has not been specified "(even though it works perfect in terminal by itself) and with subprocess it doesnt run anything
Best Practice: Completely Replacing the Shell with Python
The best approach is to not use a shell at all.
subprocess.run([
'fswebcam',
'-r', '640x480',
'--jpeg', '85',
'-D', '1',
'picture.jpg'],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Doing this with a pipeline is more complicated; see https://docs.python.org/3/library/subprocess.html#replacing-shell-pipeline, and many duplicates already on this site.
Second Choice: Using sh-compatible syntax
echo is poorly defined by the POSIX sh standard (the standard document itself advises against using it, and also fully disallows -e), so the reliable thing to do is to use printf instead.
Passing the text to be sent as a literal command-line argument ($1) gets us out of the business of figuring out how to escape it for the shell. (The preceding '_' is to fill in $0).
subprocess.run("fswebcam -r 640x480 --jpeg 85 -D 1 picture.jpg >/dev/null 2>&1",
shell=True)
string_to_send = '''From: abc#gmail.com
To: abc1#gmail.com
Subject: package for ryan
package for ryan
'''
p = subprocess.run(
[r'''printf '%s\n' "$1" | uuenview -a -bo picture.jpg | sendmail -t''',
"_", string_to_send],
shell=True)
This is running Python 2.7.5, on a CentOS Linux release 7.6.1810 (Core) system. I do not have a lot of experience with Python. But I have looked at a number of previous questions/examples and cannot figure out how to proceed with this issue. I'm unsuccessful running a Linux ssh command from a Python script. However, when I run a Linux echo command I get expected results. I'll provide the code and both outputs:
#!/bin/python
import sys
import subprocess
tunnelUser='testuser'
localIP = []
localPort = []
remoteIP = []
remotePort = []
x = 0
vfile=open('/home/'+tunnelUser+'/development/scripts/port-dummy-data','rt')
for line in vfile:
columns = line.split(',')
localIP.append(columns[0])
localPort.append(columns[1])
remoteIP.append(columns[2])
remotePort.append(columns[3])
sshCommand = " -f -N "+tunnelUser+"#"+localIP[x]+" -R "+localPort[x]\
+":"+remoteIP[x]+":"+remotePort[x]
subprocess.Popen(['/bin/ssh', sshCommand])
# subprocess.Popen(['/bin/echo', sshCommand])
x=x+1
sys.stdout.close()
Yields the following negative results:
prompt > ./create-tunnels.py
prompt > ssh: Could not resolve hostname localhost -r 8080:192.168.1.3:8080
: Name or service not known
ssh: Could not resolve hostname localhost -r 8090:192.168.1.11:8090
: Name or service not known
ssh: Could not resolve hostname localhost -r 8081:192.168.1.5:8081
: Name or service not known
ssh: Could not resolve hostname localhost -r 8085:192.168.1.9:8085
: Name or service not known
ssh: Could not resolve hostname localhost -r 8095:192.168.1.12:8095
: Name or service not known
Yet when I "comment out" the ssh and "uncomment" the echo, I get the expected results:
prompt > ./create-tunnels.py
-f -N testuser#localhost -R 8080:192.168.1.3:8080
-f -N testuser#localhost -R 8081:192.168.1.5:8081
-f -N testuser#localhost -R 8085:192.168.1.9:8085
-f -N testuser#localhost -R 8090:192.168.1.11:8090
-f -N testuser#localhost -R 8095:192.168.1.12:8095
I believe I'm missing something simple due to lack of Python experience. Any help would be appreciated.
The individual arguments to Popen() should be passed as a list, i.e. something like
Popen(['/bin/ssh', '-f', '-N', tunnelUser+"#"+localIP[x], '-R', ...])
But instead you're passing the arguments as one giant string. So it's trying to interpret the entire literal string localhost -r 8080:192.168.1.3:8080 as one hostname.
Also, why does the unsuccessful output block contain the -r flag, when the code has it as -R?
can anyone explain to me in detail to set of environment for Fred's ImageMagick Scripts in windows10 64bit and running those scripts from python?
I have installed cywin64 with UNIX bc calculator and ImageMagick and added the path to system variable and downloaded the textcleaner script and convert to .sh and try to run it from python
import subprocess
cmd = 'textcleaner.sh -g -e stretch -f 25 -o 20 -t 30 -u -s 1 -T -p 20 abbott2.jpg out.png'
subprocess.call(cmd, shell=True)
and
import subprocess
bashCommand = "sh textcleaner -g -e normalize -f 5 -o 10 -s 2 C:/Users/RahulNaidu/OneDrive/Desktop/SelvaImages/18420_0.png C:/Users/RahulNaidu/OneDrive/Desktop/SelvaImages/output.png"
process = subprocess.Popen(bashCommand.split(), shell=True, stdout=subprocess.PIPE)
output, error = process.communicate()
I am getting a new error every time so I need help in sorting out this error
You need to add the path to textcleaner and if that does not work, then add bash in front of that. The latter depends whether you have added the path to the script in your bash $PATH environment variable.
So this works for me.
import subprocess
cmd = 'bash ./textcleaner.sh -g -e stretch -f 25 -o 20 -t 30 -u -s 1 -T -p 20 abbott2.jpg out.png'
subprocess.call(cmd, shell=True)
You may get an error message about the bash "type" command not found. But that should not affect the processing of the image.
But please note that my scripts are free only for non-commercial use. Otherwise, you will need to contact me about licensing.
Please read the information and pointers for use on my home page at http://www.fmwconcepts.com/imagemagick/index.php. There are links to some documents about running on Windows. Also see https://imagemagick.org/discourse-server/viewtopic.php?f=26&t=25910
I have this bash line:
$ printf ' Number of xml files: %s\n' `find . -name '*.xml' | wc -l`
Number of xml files: 4
$
When I run it from python in this way the python interpreter stop and my terminal does not have stdout anymore::
$ ls
input aa bb
$ python
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
>>>
>>> import subprocess
>>> cmd = "printf 'xml files: %s\n' `find . -name '*.xml' | wc -l`"
>>> subprocess.check_output(['/bin/bash', cmd], shell=True)
$ ls # stdout is not seen any more I have to kill this terminal
$
Obviously the question here is not how to make this bash work from python::
>>> import subprocess
>>> cmd = "printf 'xml files: %s\n' `find . -name '*.xml' | wc -l`"
>>> out = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
>>> print(str(out.stdout, 'utf8'))
xml files: 4
>>>
The two following issues No output from subprocess.check_output() and Why is terminal blank after running python executable? does not answer the question
The short version is that check_output is buffering all the output to return. When you run ls, its standard output is going to check_output's buffer, not the terminal. When you exit the shell you are currently in, you'll get all the output at once as a single Python string.
This leads to the question, why are you getting a sub shell in the first place, instead of executing the contents of cmd? First, you are using bash wrong; its argument is a file to run, not an arbitrary command line. A more correct version of what you are doing would be
cmd = "printf 'xml files: %s\n' `find . -name '*.xml' | wc -l`"
subprocess.check_output(['/bin/bash', '-c', cmd])
or, if you want subprocess to run a shell for you, instead of explicitly executing it,
subprocess.check_output(cmd, shell=True)
Combining the list argument with shell=True is almost never what you want.
Second, given your original code, check_output first tries to combine your list into a single string, which is then joined to sh -c. That is, you try to execute something like
sh -c /bin/bash "printf 'xml files: %s\n' `find . -name '*.xml' | wc -l`"
sh runs /bin/bash, and your command string is just used as an additional argument to sh which, for the purposes of this question, we can assume is ignored. So you are in an interactive shell whose standard output is buffered instead of displayed, as described in the first part of this answer.
I had script on bash where I generated username, password, ssh-key for user.
Part for creating of ssh-key:
su $user -c "ssh-keygen -f /home/$user/.ssh/id_rsa -t rsa -b 4096 -N ''"
How can I do the same in Python with os.system? I tried this:
os.system('su %s -c "ssh-keygen -f /home/%s/.ssh/id_rsa -t rsa -b 4096 -N ''"', user)
TypeError: system() takes at most 1 argument (2 given)
Also I tried:
os.system('su user -c "ssh-keygen -f /home/user/.ssh/id_rsa -t rsa -b 4096 -N ''"')
Of course, it doesn't work either.
Format your instructions with the os package; for instance:
import os
user = 'joe'
ssh_dir = "/home/{}/.ssh/id_rsa".format(user)
os.system("ssh-keygen -f {} -t rsa -b 4096 -N ''".format(ssh_dir))
os.system is very close to a bash command line because it uses an underlying shell (like its cousins subprocess.call... using shell=True)
In your case, there's little interest using subprocess since your command runs a command, so you cannot really use argument protection by subprocess fully.
Pass the exact command, but the only change would be to protect the simple quotes, else python sees that as string end+string start (your string is protected by simple quotes already) and they're eliminated.
Check this simpler example:
>>> 'hello '' world'
'hello world'
>>> 'hello \'\' world'
"hello '' world"
that's a kind of worst-case when you cannot use either double or simple quotes to protect the string because you're using the other flavour within. In that case, escape the quotes using \:
os.system('su $user -c "ssh-keygen -f /home/$user/.ssh/id_rsa -t rsa -b 4096 -N \'\'"')
Use the subprocess module:
import subprocess
username = 'user'
result, err = subprocess.Popen(
'su %s -c "ssh-keygen -f /home/%s/.ssh/id_rsa -t rsa -b 4096 -N ''"' % (username, username),
stdout=subprocess.PIPE,
shell=True
).communicate()
if err:
print('Something went wrong')
else:
print(result)
Edit: this is the 'fast' way to do that, you should't use shell=True if you can't control the input since it allows code execution as said here