This is my code :
from subprocess import Popen, PIPE
cmd = ['antiword', 'tbhocbong151.doc']
p = Popen(cmd, stdout=PIPE)
stdout, stderr = p.communicate()
print(stdout.decode('utf-8', 'ignore'))
I have content in file word like this : "Chào bạn"
but when I generated output is: "Ch?o b?n"
How can I fix it to output like input ?
Thanks for your help
I believe that the problem is that the locale is not properly set when antiword is running. Try this:
import os
from subprocess import Popen, PIPE
myenv = dict(os.environ)
if 'LC_ALL' in myenv:
del myenv['LC_ALL']
myenv['LANG'] = 'en_US.UTF-8'
cmd = ['antiword', 'tbhocbong151.doc']
p = Popen(cmd, stdout=PIPE, env=myenv)
stdout, stderr = p.communicate()
print(stdout.decode('utf-8', 'ignore'))
If that doesn't work, try setting the LANG env variable in your shell before running your python program; e.g. by doing:
export LANG=en_US.UTF-8
Related
success python pipe stdin, out only one time this source
main.py
import subprocess from subprocess import PIPE, STDOUT
player_pipe = subprocess.Popen(["source\call.py", 'arg1'], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=True)
player_pipe.stdin.write("Send Msg\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.kill()
player_pipe.wait()
call.py
import sys
getMsg = raw_input()
print getMsg
but I want twice or more time stdin, out
so update source but it's not work
What's wrong this source
main.py (update-not work)
import subprocess from subprocess import PIPE, STDOUT
player_pipe = subprocess.Popen(["source\call.py", 'arg1'], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=True)
player_pipe.stdin.write("Send Msg\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.stdin.write("Send Msg2\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.kill()
player_pipe.wait()
call.py(update-not work)
import sys
getMsg = raw_input()
print getMsg
getMsg2 = raw_input()
print getMsg2
:D
the output of call.py is buffered. so you have to flush() it to send to main.py.
#!/usr/bin/python2
import sys
getMsg = raw_input()
print getMsg
sys.stdout.flush()
getMsg2 = raw_input()
print getMsg2
sys.stdout.flush()
Note that you need shebang #!/usr/bin/python2 at least when your OS is Linux (I don't know why OP's code works without shebang. Maybe some Windows magic ?).
Also you can use -u option not to buffer the output of python.
player_pipe = subprocess.Popen(["/usr/bin/python2","-u","./call.py"], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=False)
When you say "but I want twice or more time stdin, out", I'm not sure what you really mean.
In a basic Linux/UNIX system, you have 1 - and only one - STDIN, STDOUT, and STDERR. Now, you can pipe things in and out, treating STDERR separately if you want, but you cannot just arbitrarily assign multiple inputs without setting up separate mechanisms (sockets, etc) to handle that within your program.
success python pipe stdin, out only one time this source
main.py
import subprocess from subprocess import PIPE, STDOUT
player_pipe = subprocess.Popen(["source\call.py", 'arg1'], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=True)
player_pipe.stdin.write("Send Msg\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.kill()
player_pipe.wait()
call.py
import sys
getMsg = raw_input()
print getMsg
but I want twice or more time stdin, out
so update source but it's not work
What's wrong this source
main.py (update-not work)
import subprocess from subprocess import PIPE, STDOUT
player_pipe = subprocess.Popen(["source\call.py", 'arg1'], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=True)
player_pipe.stdin.write("Send Msg\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.stdin.write("Send Msg2\n")
get_stdout = player_pipe.stdout.readline()
print("[Get Msg]" + get_stdout)
player_pipe.kill()
player_pipe.wait()
call.py(update-not work)
import sys
getMsg = raw_input()
print getMsg
getMsg2 = raw_input()
print getMsg2
:D
the output of call.py is buffered. so you have to flush() it to send to main.py.
#!/usr/bin/python2
import sys
getMsg = raw_input()
print getMsg
sys.stdout.flush()
getMsg2 = raw_input()
print getMsg2
sys.stdout.flush()
Note that you need shebang #!/usr/bin/python2 at least when your OS is Linux (I don't know why OP's code works without shebang. Maybe some Windows magic ?).
Also you can use -u option not to buffer the output of python.
player_pipe = subprocess.Popen(["/usr/bin/python2","-u","./call.py"], stdin=PIPE,
stdout=PIPE, stderr=STDOUT, shell=False)
When you say "but I want twice or more time stdin, out", I'm not sure what you really mean.
In a basic Linux/UNIX system, you have 1 - and only one - STDIN, STDOUT, and STDERR. Now, you can pipe things in and out, treating STDERR separately if you want, but you cannot just arbitrarily assign multiple inputs without setting up separate mechanisms (sockets, etc) to handle that within your program.
In my old python script, I use the following code to show the result for Windows cmd command:
print(os.popen("dir c:\\").read())
As the python 2.7 document said os.popen is obsolete and subprocess is recommended. I follow the documentation as:
result = subprocess.Popen("dir c:\\").stdout
And I got error message:
WindowsError: [Error 2] The system cannot find the file specified
Can you tell me the correct way to use the subprocess module?
You should use call subprocess.Popen with shell=True as below:
import subprocess
result = subprocess.Popen("dir c:", shell=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output,error = result.communicate()
print (output)
More info on subprocess module.
This works in Python 3.7:
from subprocess import Popen, PIPE
args = ["echo", "realtime abc"]
p = Popen(args, stdout=PIPE, stderr=PIPE, shell=True, text=True)
for line in p.stdout:
print("O=:", line)
.
Output:
O=: "realtime abc"
For training, I have idea to write a script which will display the last bash/zsh command.
First of all, I tried with os.system and subprocess to execute history command. But, as you know, history is a shell builtin, so, it doesn't return anything.
Then, I tried this piece of code:
shell_command = 'bash -i -c "history -r; history"'
event = Popen(shell_command, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
But it have just shown commands from last session. What i want to see is the previous command (which i just typed)
I tried cat ~/.bash_history and have same result, unluckily.
Any idea ?
You could use tail to get the last line:
from subprocess import Popen, PIPE, STDOUT
shell_command = 'bash -i -c "history -r; history"'
event = Popen(shell_command, shell=True, stdin=PIPE, stdout=PIPE,
stderr=STDOUT)
out = Popen(["tail", "-n", "1"], stdin=event.stdout, stdout=PIPE)
output = out.communicate()
print(output[0])
Or just split the output and get the last line:
from subprocess import Popen, PIPE, STDOUT
shell_command = 'bash -i -c "history -r; history"'
event = Popen(shell_command, shell=True, stdin=PIPE, stdout=PIPE,
stderr=STDOUT)
print(event.communicate()[0].splitlines()[-1])
Or read bash_history:
from os import path
out= check_output(["tail","-n","1",path.expanduser("~/.bash_history")])
print(out)
Or open the file in python and just iterate until you get to the end of the file:
from os import path
with open(path.expanduser("~/.bash_history")) as f:
for line in f:
pass
last = line
print(last)
I can run this normally on the command line in Linux:
$ tar c my_dir | md5sum
But when I try to call it with Python I get an error:
>>> subprocess.Popen(['tar','-c','my_dir','|','md5sum'],shell=True)
<subprocess.Popen object at 0x26c0550>
>>> tar: You must specify one of the `-Acdtrux' or `--test-label' options
Try `tar --help' or `tar --usage' for more information.
You have to use subprocess.PIPE, also, to split the command, you should use shlex.split() to prevent strange behaviours in some cases:
from subprocess import Popen, PIPE
from shlex import split
p1 = Popen(split("tar -c mydir"), stdout=PIPE)
p2 = Popen(split("md5sum"), stdin=p1.stdout)
But to make an archive and generate its checksum, you should use Python built-in modules tarfile and hashlib instead of calling shell commands.
Ok, I'm not sure why but this seems to work:
subprocess.call("tar c my_dir | md5sum",shell=True)
Anyone know why the original code doesn't work?
What you actually want is to run a shell subprocess with the shell command as a parameter:
>>> subprocess.Popen(['sh', '-c', 'echo hi | md5sum'], stdout=subprocess.PIPE).communicate()
('764efa883dda1e11db47671c4a3bbd9e -\n', None)
>>> from subprocess import Popen,PIPE
>>> import hashlib
>>> proc = Popen(['tar','-c','/etc/hosts'], stdout=PIPE)
>>> stdout, stderr = proc.communicate()
>>> hashlib.md5(stdout).hexdigest()
'a13061c76e2c9366282412f455460889'
>>>
i would try your on python v3.8.10 :
import subprocess
proc1 = subprocess.run(['tar c my_dir'], stdout=subprocess.PIPE, shell=True)
proc2 = subprocess.run(['md5sum'], input=proc1.stdout, stdout=subprocess.PIPE, shell=True)
print(proc2.stdout.decode())
key points (like outline in my solution on related https://stackoverflow.com/a/68323133/12361522):
subprocess.run()
no splits of bash command and parameters, i.e. ['tar c my_dir']or ["tar c my_dir"]
stdout=subprocess.PIPE for all processes
input=proc1.stdout chain of output of previous one into input of the next one
enable shell shell=True