0

I am triggering a shell script using a Python script and get its exit code for further processing. I am using the subprocess module. But when I try to capture the exit code for further processing, it comes with the script's output. How can I only get the exit code?

Below is my code

import subprocess
import os


dpath = "/home/admin/temp"
password = "password"
password_bytes = bytes(password + "\n", encoding="utf-8")
proc = subprocess.Popen(
    ["sudo", "-S", "sh", os.path.join(dpath, "test1.sh"), "hello"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
).communicate(input=password_bytes)
out, err = proc

out = str(out, "utf-8").strip()

if out == "0":
    print("success")
else:
    print("fail")

# print(type(out))
print(out)

Below is my shell script

cd /home/admin
echo $1
echo $?
tripleee
  • 158,107
  • 27
  • 234
  • 292
  • Your shell script doesn't appear to do anything useful, and even that slightly badly. You should [wrap double quotes around `$1`](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable); and `echo` (like most commands) obviously doesn't care which directory it runs in. – tripleee Feb 23 '22 at 08:34

2 Answers2

0

Well, yes, proc.communicate() returns the stdout/stderr tuple.

If you want to capture the shell script's exit code, do

proc = subprocess.Popen(
    ["sudo", "-S", "sh", os.path.join(dpath, "test1.sh"), "hello"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
)
out, err = proc.communicate(input=password_bytes)
# proc.wait() is implied by `proc.communicate()`
if proc.returncode == 0:
    print("success")

That will of course mean your script needs to communicate using the status code too:

cd /home/admin
echo $1
exit $?  # <- exit with the last command's status code
AKX
  • 123,782
  • 12
  • 99
  • 138
  • Hi @AKX Thanks for your reply ..I am getting the following error when i add proc.wait() "AttributeError: 'tuple' object has no attribute 'wait'" – tony frank Feb 23 '22 at 06:48
  • Then you didn't use the code I posted, but added `wait()` to what you have. If you pay close attention, there is no `.communicate()` at the end of the `proc = ...` assignment. – AKX Feb 23 '22 at 06:49
  • 1
    wait() is unneeded, since [communicate](https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate) already waits. – FMc Feb 23 '22 at 06:51
  • @FMc Good point, fixed. – AKX Feb 23 '22 at 06:52
  • oh sorry!.. my bad.. Thank you for you help.. The above code works great.. – tony frank Feb 23 '22 at 06:57
0

You should generally prefer the higher-level functions and avoid bare Popen when you can. The legacy call function does exactly what you are asking. The more modern run is more versatile, though.

import subprocess
import os


dpath = "/home/admin/temp"
password = "password"
proc = subprocess.run(
    ["sudo", "-S", "sh", os.path.join(dpath, "test1.sh"), "hello"],
    stdin=subprocess.DEVNULL,
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    input=password,
    # avoid having to explicitly encode
    text=True)
print("success" if proc.returncode==0 else "fail")

If you don't want to discard the output from the process, maybe switch to capture_output=True; in the absence of either, the output will simply be displayed to the user, outside of Python's control.

tripleee
  • 158,107
  • 27
  • 234
  • 292