Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending piped commands via python3 subprocess

I am trying to execute the following subprocess command via python3.4

cd /home/mailer-domains/domain | rndc loadkeys domain

I have tried numerous methods using .call and .Popen but it either doesn't like my pipe or it doesn't like my switch

>>> subprocess.call(['cd /home/mailer-domains/'+domain, '|', 'rndc', 'loadkeys', domain])    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/subprocess.py", line 537, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/local/lib/python3.4/subprocess.py", line 859, in __init__
    restore_signals, start_new_session)
  File "/usr/local/lib/python3.4/subprocess.py", line 1457, in _execute_child
    raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'cd /home/mailer-domains/lecomm.com'

>>> subprocess.call(['cd /home/ex-mailer-domains/'+domain, '&&', 'rndc', 'loadkeys', domain]) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/subprocess.py", line 537, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/local/lib/python3.4/subprocess.py", line 859, in __init__
    restore_signals, start_new_session)
  File "/usr/local/lib/python3.4/subprocess.py", line 1457, in _execute_child
    raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'cd /home/mailer-domains/lecomm.com'


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain, '&&', 'rndc', 'loadkeys', domain])
cd: too many arguments
2


>>> subprocess.Popen(['cd', '/home/mailer-domains/'+domain, '&&', 'rndc', 'loadkeys', domain])    
<subprocess.Popen object at 0x805aa5860>
cd: too many arguments


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain] '&&' ['rndc', 'loadkeys', domain])    
  File "<stdin>", line 1
    subprocess.call(['cd', '/home/mailer-domains/'+domain] '&&' ['rndc', 'loadkeys', domain])
                                                                 ^
SyntaxError: invalid syntax


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain], '&&' ['rndc', 'loadkeys', domain])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: string indices must be integers


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain], ['rndc', 'loadkeys', domain])     
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/subprocess.py", line 537, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/local/lib/python3.4/subprocess.py", line 767, in __init__
    raise TypeError("bufsize must be an integer")
TypeError: bufsize must be an integer


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain] ['rndc', 'loadkeys', domain])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list indices must be integers, not tuple


>>> subprocess.call(['cd', '/home/mailer-domains/'+domain] +['rndc', 'loadkeys', domain])
cd: too many arguments
2


>>> ps = subprocess.Popen((['cd', '/home/mailer-domains/'+domain]), stdout = subprocess.PIPE)        
>>> output = subprocess.check_output((['rndc', 'loadkeys', domain]), stdin=ps.stdout)
rndc: 'loadkeys' failed: not found
no matching zone 'lecomm.com' in any view
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.4/subprocess.py", line 620, in check_output
    raise CalledProcessError(retcode, process.args, output=output)
subprocess.CalledProcessError: Command '['rndc', 'loadkeys', 'lecomm.com']' returned non-zero exit status 1


>>> output = subprocess.check_output((['rndc', 'loadkeys', domain]), stdin=ps.stdout, stdout=PIPE)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'PIPE' is not defined

How do I properly send 2 piped commands via Python3 subprocess?

like image 249
doeJ Avatar asked Dec 13 '15 23:12

doeJ


2 Answers

The answer can be found in the subprocess documentation.

The functions from the subprocess module normally do not call a shell to interpret the commands, but rather invoke them directly with the given arguments! This behaviour can be overidden by using the argument shell=True (example from the Python documentation):

output = check_output("dmesg | grep hda", shell=True)

However, this is not advisable if the command and arguments are not fix but depends on user input. Then, the correct way to do this is to use two Popen calls and construct the pipeline by hand (code example again from the Python documentation):

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]
like image 57
Sebastian Riese Avatar answered Nov 15 '22 07:11

Sebastian Riese


You don't need pipes at all, just pass the cwd to to subprocess:

subprocess.call(['rndc', 'loadkeys', domain],cwd='/home/mailer-domains/'+domain)

If you did wanted to change directory for more than just the subprocess, you should use os.chdir.

like image 24
Padraic Cunningham Avatar answered Nov 15 '22 06:11

Padraic Cunningham