Subprocess returns exit status 1 - python

When I run a command through subprocess I get exit status 1 without my print or the error raised.
here is my code:
def generate_model(self):
if not ((self.username == None) or (self.password == None) or (self.database == None)):
cmd = "python -m pwiz -e %s -H %s -u %s -P %s %s > %s"%(self.engine,self.host,self.username,self.password,self.database,self.database+".py")
print subprocess.check_call(cmd)
else:
raise ValueError
command asks an input once terminal is opened. After that it closes with exit status 1
When I run the same command directly in command prompt it works fine

subprocess.check_call() does not run the shell by default and therefore the redirection operator > won't work. To redirect stdout, pass stdout parameter instead:
with open(filename, 'wb', 0) as file:
check_call([sys.executable, '-m', 'pwiz', '-e', ...], stdout=file)
Related: Python subprocess.check_output(args) fails, while args executed via Windows command line work OK.

Related

Not able to run command via wsl.exe

I'm trying to run this commands from a python script:
def raw(path_avd_py, path_avd, snp_name, out_file):
if OS == 'Windows':
cmd_raw = f"wsl.exe -e sh -c 'python3 {path_avd_py} -a {path_avd}
-s {snp_name} -o {out_file}'"
else:
cmd_raw = f'python3 {path_avd_py} -a {path_avd} -s {snp_name} -o {out_file}'
subprocess.Popen(cmd_raw, shell=True)
time.sleep(25)
return None
def idiffer(i_path, raw_1, raw_2, path, state):
if OS == 'Windows':
cmd_idiff = f"wsl.exe -e sh -c 'python3 {i_path} {raw_1} {raw_2}'"
[...]
file = os.path.join(path, f'{state}.idiff')
with open(file, 'w') as f:
subprocess.Popen(cmd_idiff, stdout=f, text=True)
If im executing cmd_raw with subprocess.run from a python-shell (Powershell), things are working. If im try running this via script, this exception occurs, using different shells:
-e sh: avdecrypt-master\avdecrypt.py: 1: Syntax error: Unterminated quoted string
-e bash: avdecrypt-master\avdecrypt.py: -c: line 0: unexpected EOF while looking for matching `''
avdecrypt-master\avdecrypt.py: -c: line 1: syntax error: unexpected end of file
I already tried os.system, os.run([list]) no change.
Thanks for the help!
For those who have a similar question, I found a solution, which is working for me:
Apparently calling scripts with some argv has to be in one single quotation mark and can be executed via run (in my case important, because the process has to be terminated). This leads to a form like:
cmd = ['wsl.exe', '-e', 'bash', '-c', '-a foo -b bar [...]']
subprocess.run(cmd, shell=True)
Lib shlex is helping here and formatting the strings like subprocess is needing it:
cmd_finished = shlex.split(cmd)
https://docs.python.org/3/library/shlex.html

Failed to execute command line argument from python script

I am trying to run a command line argument through python script. Script triggers the .exe but it throws an error as System.IO.IOException: The handle is invalid..
Following is my code :
import os , sys , os.path
from subprocess import call
import subprocess, shlex
def execute(cmd):
"""
Purpose : To execute a command and return exit status
"""
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:
print "Error: failed to execute command:",cmd
print error
return result
found_alf = r"C:\AniteSAS\ResultData\20170515\Run01\1733200515.alf"
filter_alvf = r"C:\Users\sshaique\Desktop\ALF\AniteLogFilter.alvf"
command = str(r'ALVConsole.exe -e -t -i ' + '\"'+found_alf+'\"' + ' --ffile ' + '\"'+filter_alvf+'\"')
print command
os.chdir('C:\Program Files\Anite\LogViewer\ALV2')
print os.getcwd()
print "This process detail: \n", execute(command)
Output is as follows :
ALVConsole.exe -e -t -i "C:\AniteSAS\ResultData\20170515\Run01\1733200515.alf" --ffile "C:\Users\sshaique\Desktop\ALF\AniteLogFilter.alvf"
C:\Program Files\Anite\LogViewer\ALV2
This process detail:
Error: failed to execute command: ALVConsole.exe -e -t -i "C:\AniteSAS\ResultData\20170515\Run01\1733200515.alf" --ffile "C:\Users\sshaique\Desktop\ALF\AniteLogFilter.alvf"
Unhandled Exception: System.IO.IOException: The handle is invalid.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean& succeeded)
at ALV.Console.CommandLineParametersHandler.ConsoleWriteLine(String message, Boolean isError)
at ALV.Console.CommandLineParametersHandler.InvokeActions()
at ALV.Console.Program.Main(String[] args)
When I copy the command line argument from the above output and run manually from cmd it works fine.
ALVConsole.exe -e -t -i "C:\AniteSAS\ResultData\20170515\Run01\1733200515.alf" --ffile "C:\Users\sshaique\Desktop\ALF\AniteLogFilter.alvf"
I am using Windows 7 and Python 2.7.13 for. Please suggest overcoming this issue.
EDIT:
I have also tried to pass command as a list s as per below code but the issue remains the same.
command = str(r'ALVConsole.exe -e --csv -i ' + '\"'+found_alf+'\"' + ' --ffile ' + '\"'+filter_alvf+'\"')
s=shlex.split(command)
print s
print "This process detail: \n", execute(s)
Based on your error messages I think that this problem is with ALVConsole.exe, not your Python script.
When you redirect the output, ALVConsole.exe tries to do something to the console (like setting cursor position, or getting the size of the terminal) but fails like this.
Is there a flag to ALVConsole.exe that modifies the output to a machine-readable version? I wasn't able to find the documentation for this program.

Python subprocess returncode takes on different values

I'm running a python script demo.py which is as follows:
#!/usr/bin/env python
from subprocess import Popen, PIPE, CalledProcessError
try:
process = Popen(["/root/script.sh"], stdout = PIPE, stderr = PIPE)
process_out, process_err = process.communicate()
return_code = process.returncode
if process_out:
print "output:", process_out
if process_err:
print "error:", process_err
print "return code:", return_code
except CalledProcessError as e:
print "CalledProcessError:", e
except Exception, fault:
print "fault:", fault
script.sh is as follows:
#!/bin/bash
cd /root/
mkdir foo
cd foo
cat << EOF > bar.txt
random text
EOF
The directory foo already exists. Hence, script.sh should fail and it does. demo.py correctly catches the error in process_err and prints it:
error: mkdir: cannot create directory `foo': File exists
But the value of return_code is still 0 (which indicates successful run).
If my script.sh is as follows:
#!/bin/bash
cd /root/
mkdir foo
process_err prints the same error message but now the value of return_code is 1.
Where is the problem?
Please also suggest scenarios in which process.returncode takes on values other than 0 and 1.
This is not a problem with Python, but with your Bash script that is continuing execution after mkdir. This is how Bash works by default, you have to tell it to exit when it encounters an error.
Use:
#!/bin/bash
set -e
Or, if you can't change the Bash script and you can only change the Python code:
process = Popen(['bash', '-e', '/root/script.sh'], stdout = PIPE, stderr = PIPE)
From help set:
-e Exit immediately if a command exits with a non-zero status.

subprocess ssh command fails for some commands but not others (command works in terminal)

As part of a python script, I am hoping to capture the output of a shell command executed via ssh, namely
ssh User#999 screen -list
If I execute the above command directly in terminal, I get the results I need. However, when executing through subprocess.check_output as below, I get a non-zero exit status 1 error.
I am able to execute other commands via ssh and capture the output without problem.
Is there something specific about screen -list that does not like being called in this fashion?
import subprocess
srvr = 'User#999.99.999.9'
print("CMD 1: ===============")
cmd1 = "ssh " + srvr + " ls -l"
print ("COMMAND IS ..... " + cmd1 + "\n")
out1 = subprocess.check_output(cmd1, shell=True)
print(out1 + "\n")
print("CMD 2: ===============")
cmd2 = "ssh " + srvr + " screen -list"
print ("COMMAND IS ..... " + cmd2 + "\n")
out2 = subprocess.check_output(cmd2, shell=True)
print(out2 + "\n")
Error:
subprocess.CalledProcessError: Command '['ssh User#999.99.999.9 screen', '-list']' returned non-zero exit status 1
subprocess.check_output check the exit code of the subprocess; and it raises exception if the exit code is not zero.
If you don't care about exit code, use subprocess.Popen.communicate:
out1, err1 = subprocess.Popen(cmd1,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
That's how subprocess.check_output() is supposed to work. See: http://docs.python.org/2/library/subprocess.html
The command on your server is returning a non zero return code and thus is raising the appropriate Exception CalledProcessError.

How to log errors in python when using the os module

I'm trying to incorporate a simple way to keep track of a periodic mysqldump command I want to run using the os module in python. I've written this, but in testing it doesn't raise the exception, even when the mysqldump command completes with an error. I'm pretty new to python, so I might be approaching this terribly, but I thought I would try to get pointed in the right direction.
db_dump = "mysqldump -u %s -p%s --socket=source_socket --databases %s | mysql -u %s -p%s --socket=dest_socket" % (db_user, db_pass, ' '.join(db_list), db_user, db_pass)
try:
os.system(db_dump)
except:
logging.error("databases did not dump")
else:
logging.info("database dump complete")
os.system is not a very robust or powerful way to call system commands, I'd recommend using subprocess.check_output() or subprocess.check_call
ie,
>>> cmd = 'ls -l'
>>> badcmd = 'ls /foobar'
>>> subprocess.check_call(cmd.split())
0
>>> subprocess.check_call(badcmd.split())
ls: /foobar: No such file or directory
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 511, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', '/foobar']' returned non-zero exit status 1
os.system() returns an integer result code. When it returns 0, the command ran successfully; when it returns a nonzero value, that indicates an error.
db_dump = "mysqldump -u %s -p%s --socket=source_socket --databases %s | mysql -u %s -p%s --socket=dest_socket" % (db_user, db_pass, ' '.join(db_list), db_user, db_pass)
result = os.system(db_dump)
if 0 == result:
logging.info("database dump complete")
else:
logging.error("databases did not dump; result code: %d" % result)
Like #COpython, I recommend the use of subprocess. It is a bit more complicated than os.system() but it is tremendously more flexible. With os.system() the output is sent to the terminal, but with subprocess you can collect the output so you can search it for error messages or whatever. Or you can just discard the output.
Here is what I would do.
import logging
import subprocess
log = logging.getLogger(__name__)
cmd = "mysqldump -u %s -p%s --socket=source_socket --databases %s | mysql -u %s -p%s " \
"--socket=dest_socket" % (db_user, db_pass, ' '.join(db_list), db_user, db_pass)
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE.PIPE)
stdout, stderr = process.communicate()
stdout = [x for x in stdout.split("\n") if x != ""]
stderr = [x for x in stderr.split("\n") if x != ""]
if process.returncode < 0 or len(stderr):
for error in stderr:
log.error(error)

Categories

Resources