1

I am working on something like compile , and i am trying to compile assembler and get the output information about it using subprocess.

When I am using subprocess.call every thing works fine like :

(I add some spam to it so it will output a error)

Version : Python3.5

In [12]: subprocess.call(['as','-32','test.s'])
test.s: Assembler messages:
test.s:3: Error: no such instruction: `zxvasdf'
Out[12]: 1

But when i use subprocess.getoutput :

In [13]: subprocess.getoutput(['as','-32','test.s'])

It just freeze and do nothing .

How can i solve this problem ?

Thanks for any advice .

KIDJourney
  • 1,200
  • 1
  • 9
  • 22

3 Answers3

3

The issue as @Lex Scarisbrick correctly noticed is that getoutput(cmd) expects a shell command as a string. If you pass it a list; the additional arguments are passed to the shell on POSIX, not to the 'as' process itself. It means that 'as' program is run without any command-line arguments.

It just freeze and do nothing .

It seems as invoked without command-line arguments waits for its input on stdin. You may start typing some assembler and press Ctrl+D to indicate EOF. If you don't provide input; it will hang forever.

See Why subprocess.Popen doesn't work when args is sequence?

If you want to read both stdout, stderr from 'as' subprocess; you could use subprocess.run():

#!/usr/bin/env python3
import subprocess

p = subprocess.run(['as','-32','test.s'],
                   stdout=subprocess.PIPE,
                   stderr=subprocess.PIPE, # capture separately 
                   universal_newline=True) # decode bytes
print("Status: {p.returncode}, stdout: {p.stdout}, stderr: {p.stderr}".format(p=p))

Note: don't use shell=True here.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
1

subprocess.getouput() doesn't take a list as input like subprocess.call() does. It takes a single argument as a string. Change it to:

subprocess.getoutput('as -32 test.s')
Lex Scarisbrick
  • 1,540
  • 1
  • 24
  • 31
  • you should try `subprocess.getoutput(['ls','-a'])` – KIDJourney May 14 '16 at 02:43
  • It only takes the first argument. `getoutput('ls -a')` returns different output than `getoutput(['ls','-a'])`. Because only the first argument is taken, in the above question, the `as` command hangs waiting for input. – Lex Scarisbrick May 14 '16 at 03:04
  • args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names). If passing a single string, either shell must be True (see below) or else the string must simply name the program to be executed without specifying any arguments. – KIDJourney May 14 '16 at 03:06
  • Totally willing to admit I'm wrong. I'm only going on behavior with a CPython 3.5.1 virtual environment. Maybe the docs are wrong? My test case was something else that would expect to read from stdin if it were missing arguments. I tried `subprocess.getoutput('cat /etc/hosts')` which worked and `subprocess.getoutput(['cat','/etc/hosts'])` which hung like described in the question. When I sent a ^C to break out, the bottom of the Traceback was `stdout = self.stdout.read()`, which seemed to make sense. What am I missing? – Lex Scarisbrick May 14 '16 at 03:18
  • @KIDJourney: if it doesn't produce an error; it doesn't mean that it works: try `getoutput("""python -c 'print("works")'""")` vs. `getoutput(['python', '-c', 'print("does not works on *nix")'])` (the latter won't work on POSIX systems). It is an excusable error e.g., [PyMOTW has it (for many years now)](https://pymotw.com/2/subprocess/) – jfs May 14 '16 at 03:51
  • @LexScarisbrick Sorry for my rudeness , It seems i have misunderstood it , – KIDJourney May 14 '16 at 06:14
  • @J.F.Sebastian Thanks for the correction , I didn't look over document carefully enough . – KIDJourney May 14 '16 at 06:17
  • @KIDJourney: No worries. At all. – Lex Scarisbrick May 14 '16 at 12:48
0

Well , it seems i can use subprocess.PIPE to solve the problem .

In [16]: proc = subprocess.Popen(['as','-32','test.s'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)

In [17]: for i in proc.stderr:
   ....:     print(i)
   ....:     
b'test.s: Assembler messages:\n'
b"test.s:3: Error: no such instruction: `zxvasdf'\n"

But i don't quite understand why i goes well .

I am going to check the document for more details .

Thanks for everyone .

KIDJourney
  • 1,200
  • 1
  • 9
  • 22
  • do not pass PIPE unless you read from the pipe while the process is still running otherwise a deadlock may happen. – jfs May 14 '16 at 03:38