Unable to get result from stdout with subprocess

2019-07-15 06:05发布

问题:

I need to get the result being displayed in the console after issuing a command.

e.g.: H:/path/to/openssl.exe x509 -in H:/path/to/cert.pem -noout -subject

This command produces values of an encrypted certificate when placed in an opened cmd.exe but I am unable to get the same result as a returned variable using the subprocess module.

So far I have attempted (where cmd is the e.g. above):

# checking if output is going to stderr
out = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
# attempt with Popen
out = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).communicate()[0]
# attempt with Popen not using communicate()
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
out = p.stdout.read()

All the print (out) values are b''.

I have even broken the cmd into multiple args for both check_output() and Popen() such that it would look like: ["H:/path/to/openssl.exe", "x509 -in H:/path/to/cert.pem -noout -subject"].

I do have an alternative method to achieve the result, but that requires running a .bat file that contains the command: start cmd /k "... > H:/path/to/temp.txt" where the ... is the command in question here. This redirects the .exe output to a temp file (for security purposes) which I delete after reading contents into a variable.

Supporting information:

If the first part of the command is run (the .exe) it opens custom console for that program. The remainder of the command is executed in that console and then that console closes. However if the whole command series is used in a cmd.exe console, the output is displayed in that console. Hence why the use of " " in my alternate method of a .bat as it issues it to the open console as a whole command.

Use of subprocess.Popen(["cmd.exe"]) opens a console at C:\Python36> and I can issue the command in question and get the exact result I want. I cannot seem to grab it pythonically though. However, subprocess.Popen(["cmd.exe", "H:/path/to/openssl.exe"]) does not execute the second command; opens a console but does not start the .exe console.

Update:

I was able to get a result, but I don't like how I got there. Is there a shorter way to do the following:

p = subprocess.Popen("H:/path/to/openssl.exe", stdin=PIPE, stdout=PIPE)
# b for byte-type requirement
p.stdin.write(b"x509 -in H:/path/to/cert.pem -noout -subject")
p.stdin.close()
out = p.stdout.read()

I can also produce the result with:

p = os.popen("start cmd /k H:/path/to/openssl.exe -in H:/path/to/cert.pem -noout -subject")

Tried to add .read() to the above, but prints a blank line

回答1:

i am not used to use python on windows, but try the following. Don't use shell=True, instead try with this cmd:

cmd = ["H:/path/to/openssl.exe", "x509", "-in", "H:/path/to/cert.pem", "-noout", "-subject"]


回答2:

Have you tried storing the entire command as raw string and passing it with shell=True

cmd = r'H:/path/to/openssl.exe x509 -in H:/path/to/cert.pem -noout -subject' p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = p.communicate() print(out[0]) #for std out print(out[1]) # for std err

Edit: This worked for me with stderr,

print p.communicate()[1]

b'unable to load certificate\r\n3636:error:0D07209B:asn1 encoding routines:ASN1_ get_object:too long:./crypto/asn1/asn1_lib.c:142:\r\n3636:error:0D068066:asn1 en coding routines:ASN1_CHECK_TLEN:bad object header:./crypto/asn1/tasn_dec.c:1281: \r\n3636:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 erro r:./crypto/asn1/tasn_dec.c:380:Type=X509\r\n3636:error:0906700D:PEM routines:PEM _ASN1_read_bio:ASN1 lib:./crypto/pem/pem_oth.c:83:\r\n'